I'm creating a component from TNetHTTPClient, and i like to overload the events (procedure declared in private section in TNetHTTPClient) :
TNetHTTPClient = class(TComponent)
private
procedure DoOnRequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);
procedure DoOnRequestError(const Sender: TObject; const AError: string);
procedure DoOnReceiveData(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean);
But i can't call them from my class : like this.
TRequestAccess = class(TNetHTTPClient)
private
procedure ShowLoadAnimation ;
procedure HideLoadAnimation ;
procedure DoOnRequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse); override;
procedure DoOnRequestError(const Sender: TObject; const AError: string); override;
procedure DoOnReceiveData(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean); override;
...
procedure TRequestAccess.DoOnReceiveData(const Sender: TObject; AContentLength,
AReadCount: Int64; var Abort: Boolean);
begin
self.HideLoadAnimation ;
inherited;
end;
procedure TRequestAccess.DoOnRequestCompleted(const Sender: TObject;
const AResponse: IHTTPResponse);
begin
self.HideLoadAnimation ;
inherited;
end;
procedure TRequestAccess.DoOnRequestError(const Sender: TObject;
const AError: string);
begin
self.HideLoadAnimation ;
inherited;
end;
ShowLoadAnimation and HideLoadAnimation are 2 functions to automatically show and hide a TAniIndicator.
Seems i can't override because it's declared in private and non virtual ?
how can i do this ?
I think i can't rewrite my own function because there is a thread..
procedure TNetHTTPClient.DoOnRequestError(const Sender: TObject; const AError: string);
begin
if Assigned(FOnRequestError) then
TThread.Synchronize(nil, procedure
begin
FOnRequestError(Sender, AError);
end);
end;
this work properly. official method from embarcadero.
unit NetHTTPClientUnit;
interface
uses
System.SysUtils, System.Classes, System.Net.HttpClientComponent,System.Net.HttpClient,System.Net.URLClient;
type
TNewNetHTTPClient = class(TNetHTTPClient)
private
FOnAuthEventInternal : TCredentialsStorage.TCredentialAuthevent;
FOnReceiveDataInternal : TReceiveDataEvent;
FOnRequestCompletedInternal : TRequestCompletedEvent;
FOnRequestErrorInternal : TRequestErrorEvent;
function GetAuthEventOverride: TCredentialsStorage.TCredentialAuthevent;
procedure SetAuthEventOverride(const Value: TCredentialsStorage.TCredentialAuthevent);
function GetOnReceiveData: TReceiveDataEvent;
function GetOnRequestCompleted: TRequestCompletedEvent;
function GetOnRequestError: TRequestErrorEvent;
procedure SetOnReceiveData(const Value: TReceiveDataEvent);
procedure SetOnRequestCompleted(const Value: TRequestCompletedEvent);
procedure SetOnRequestError(const Value: TRequestErrorEvent);
{ Private declarations }
procedure InternalReceiveDataEvent(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean);
procedure InternalRequestErrorEvent(const Sender: TObject; const AError: string);
procedure InternalRequestCompletedEvent(const Sender: TObject; const AResponse: IHTTPResponse);
procedure InternalAuthEvent(const Sender: TObject;
AnAuthTarget: TAuthTargetType; const ARealm, AURL: string; var AUserName,
APassword: string; var AbortAuth: Boolean;
var Persistence: TAuthPersistenceType);
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent); override;
published
/// <summary> UserName needed to be authenticated to the proxy</summary>
property OnAuthEvent: TCredentialsStorage.TCredentialAuthevent read GetAuthEventOverride write SetAuthEventOverride;
/// <summary> Event fired when a request finishes</summary>
property OnRequestCompleted: TRequestCompletedEvent read GetOnRequestCompleted write SetOnRequestCompleted;
/// <summary> Event fired when a request has an error</summary>
property OnRequestError: TRequestErrorEvent read GetOnRequestError write SetOnRequestError;
/// <summary>Property to manage the ReceiveData Event</summary>
property OnReceiveData: TReceiveDataEvent read GetOnReceiveData write SetOnReceiveData;
end;
procedure Register;
implementation
Uses WinApi.Windows;
procedure Register;
begin
RegisterComponents('Net', [TNewNetHTTPClient]);
end;
{ TNewNetHTTPClient }
constructor TNewNetHTTPClient.Create(AOwner: TComponent);
begin
inherited;
inherited OnAuthEvent := InternalAuthEvent;
inherited OnRequestCompleted := InternalRequestCompletedEvent;
inherited OnRequestError := InternalRequestErrorEvent;
inherited OnReceiveData := FOnReceiveDataInternal;
end;
function TNewNetHTTPClient.GetAuthEventOverride: TCredentialsStorage.TCredentialAuthevent;
begin
Result := FOnAuthEventInternal;
end;
function TNewNetHTTPClient.GetOnReceiveData: TReceiveDataEvent;
begin
result := FOnReceiveDataInternal;
end;
function TNewNetHTTPClient.GetOnRequestCompleted: TRequestCompletedEvent;
begin
Result := FOnRequestCompletedInternal;
end;
function TNewNetHTTPClient.GetOnRequestError: TRequestErrorEvent;
begin
Result := FOnRequestErrorInternal;
end;
procedure TNewNetHTTPClient.InternalAuthEvent(const Sender: TObject;
AnAuthTarget: TAuthTargetType; const ARealm, AURL: string; var AUserName,
APassword: string; var AbortAuth: Boolean;
var Persistence: TAuthPersistenceType);
begin
OutputDebugString('InternalAuthEvent');
if Assigned(FOnAuthEventInternal) then
FOnAuthEventInternal(Sender, AnAuthTarget, ARealm, AURL,AUserName,APassword,AbortAuth,Persistence);
end;
procedure TNewNetHTTPClient.InternalReceiveDataEvent(const Sender: TObject;
AContentLength, AReadCount: Int64; var Abort: Boolean);
begin
OutputDebugString('InternalReceiveDataEvent');
if Assigned(FOnReceiveDataInternal) then
FOnReceiveDataInternal(Sender, AContentLength, AReadCount, Abort);
end;
procedure TNewNetHTTPClient.InternalRequestCompletedEvent(const Sender: TObject;
const AResponse: IHTTPResponse);
begin
OutputDebugString('RequestCompletedEvent');
if AResponse <> nil then
OutputDebugString( PChar(AResponse.ContentEncoding));
if Assigned(FOnRequestCompletedInternal) then
FOnRequestCompletedInternal(Sender,AResponse);
end;
procedure TNewNetHTTPClient.InternalRequestErrorEvent(const Sender: TObject;
const AError: string);
begin
OutputDebugString(PChar('RequestErrorEvent ' + AError));
if Assigned(FOnRequestErrorInternal) then
FOnRequestErrorInternal(Sender,AError);
end;
procedure TNewNetHTTPClient.SetAuthEventOverride(
const Value: TCredentialsStorage.TCredentialAuthevent);
begin
FOnAuthEventInternal := Value;
end;
procedure TNewNetHTTPClient.SetOnReceiveData(const Value: TReceiveDataEvent);
begin
FOnReceiveDataInternal := Value;
end;
procedure TNewNetHTTPClient.SetOnRequestCompleted(
const Value: TRequestCompletedEvent);
begin
FOnRequestCompletedInternal := Value;
end;
procedure TNewNetHTTPClient.SetOnRequestError(const Value: TRequestErrorEvent);
begin
FOnRequestErrorInternal := Value;
end;
end.
Related
I have a nested structure definition flatened into a slice (this hypothesis is not negociable, I have to deal with it) :
type element struct {
Name string
Type string // can be basic type string (eg "uint8")
// or a definition.ID for nested struct
}
type definition struct {
ID string
Elements []element
}
type definitions []definition
allDefs := definitions{
{
ID: "root",
Elements: []element{
{
Name: "SubStruct",
Type: "sub1", // this is reference to another definition
},
{
Name: "VarU32",
Type: "uint32", // this is a basic type string representation
},
},
},
{
ID: "sub1",
Elements: []element{
{
Name: "VarU8",
Type: "uint8",
},
{
Name: "VarU16",
Type: "uint16",
},
},
},
}
And I would like to build the corresponding nested struct using a recursive method (don't know the real depth) :
func (defs definitions) getStruct(id string) interface{} {
for _, def := range defs {
if def.ID == id { // found a reference to definition
fields := []reflect.StructField{}
for _, e := range def.Elements {
s := defs.getStruct(e.Type)
fields = append(fields, reflect.StructField{
Name: e.Name,
Type: reflect.TypeOf(s),
Tag: "",
})
}
return reflect.New(reflect.StructOf(fields)).Interface()
}
}
// didn't found a reference to a definition, it should be a basic type
if id == "uint8" {
return reflect.ValueOf(uint8(0)).Interface()
}
if id == "uint16" {
return reflect.ValueOf(uint16(0)).Interface()
}
if id == "uint32" {
return reflect.ValueOf(uint32(0)).Interface()
}
// ignore the fact id could be anything else for this example
return nil
}
root := allDefs.getStruct("root")
// using spew to inspect variable : github.com/davecgh/go-spew/spew
spew.Dump(root)
// (*struct { SubStruct *struct { VarU8 uint8; VarU16 uint16 }; VarU32 uint32 })(0xc00004e400)({
// SubStruct: (*struct { VarU8 uint8; VarU16 uint16 })(<nil>),
// VarU32: (uint32) 0
// })
Then I want to be able to assign some variable's values :
rootValElem := reflect.ValueOf(root).Elem()
rootValElem.FieldByName("VarU32").SetUint(1)
spew.Dump(root)
// (*struct { SubStruct *struct { VarU8 uint8; VarU16 uint16 }; VarU32 uint32 })(0xc00004e400)({
// SubStruct: (*struct { VarU8 uint8; VarU16 uint16 })(<nil>),
// VarU32: (uint32) 1
// })
Setting root level variable value is OK, but I am unable to entering Sub level and assign any variable, no matter how I play with reflect ValueOf()/Elem()/Addr()..., here are some examples :
fieldSub := rootValElem.FieldByName("SubStruct")
// fieldSub.Kind() : ptr
// fieldSub.CanSet() : true
subVal := reflect.ValueOf(fieldSub)
// subVal.Kind() : struct
// subVal.CanSet() : false
fieldU16 := subVal.FieldByName("VarU16")
// fieldU16.Kind() : invalid
// fieldU16.CanSet() : false
fieldSubElem := fieldSub.Elem()
// fieldSubElem.Kind() : invalid
// fieldSubElem.CanSet() : false
fieldU16 := fieldSubElem.FieldByName("VarU16")
// panic: reflect: call of reflect.Value.FieldByName on zero Value
Thanks to mkopriva comment above, I understand now my mistake : fieldSub is a pointer and I should check if nil, then allocate the struct value before trying to get Elem() then Field :
fieldSub := rootValElem.FieldByName("SubStruct")
// fieldSub.Kind() : ptr
// fieldSub.CanSet() : true
// fieldSub.IsNil() : true
if fieldSub.IsNil() && fieldSub.CanSet() {
fieldSub.Set(reflect.New(fieldSub.Type().Elem()))
}
fieldU8 := fieldSub.Elem().FieldByName("VarU8")
// fieldSub.Kind() : uint8
// fieldSub.CanSet() : true
if fieldU8.CanSet() {
fieldU8.SetUint(8)
}
spew.Dump(root)
// (*struct { SubStruct *struct { VarU8 uint8; VarU16 uint16 }; VarU32 uint32 })(0xc00008a3f0)({
// SubStruct: (*struct { VarU8 uint8; VarU16 uint16 })(0xc0000ac430)({
// VarU8: (uint8) 8,
// VarU16: (uint16) 0
// }),
// VarU32: (uint32) 1
// })
I am getting this when I try to initialize a map in a struct. Here's the code:
//some code above
storageNodes[id].blocks = make(map[int64]Block)//error here
storageNodes[id].blocks[0] = generateBlockOfRandomFiles()
//some code below
//in a separate file
type StorageNode struct {
*Node
blocks map[int64]Block
}
What am I missing here?
Direct assignment to non-pointer map values is illegal in Go.
type Node struct{ /* ... */ }
type Block struct{ /* ... */ }
type StorageNode struct {
*Node
blocks map[int64]Block
}
// ...
storageNodes := map[int]StorageNode{123: {}}
storageNodes[123].blocks = map[int64]Block{987: {}} // illegal
Use pointers:
storageNodes := map[int]*StorageNode{123: {}}
storageNodes[123].blocks = map[int64]Block{987: {}}
fmt.Println(storageNodes[123].blocks) // block 987 is present
Or, use temporary variable and re-assign once modified:
storageNodes := map[int]StorageNode{123: {}}
sn := storageNodes[123] // read
sn.blocks = map[int64]Block{987: {}} // modify
storageNodes[123] = sn // write back to map
fmt.Println(storageNodes[123].blocks) // block 987 is present
I am trying to create a GUI with a series of text entry fields:
package main
import ("github.com/andlabs/ui")
func main() {
ui.Main(makeMainWin)
}
func makeMainWin(){
var entlist = []ui.NewEntry //Error here. How to declare an array of ui.NewEntry?
var box = ui.NewVerticalBox()
for i,_ := range [5]int{} {
println(i)
box.Append(ui.NewEntry(), false)
}
var mainWindow = ui.NewWindow("Hello", 200, 100, false)
mainWindow.SetChild(box)
mainWindow.OnClosing( func (*ui.Window) bool {
ui.Quit(); return true } )
mainWindow.Show()
}
However, there is error on var entlist = []NewEntry
I am not able to create an array of NewEntry components. I have tried []ui.NewEntry, []*ui.NewEntry, []ui.NewEntry() and []*ui.NewEntry()
Where is the problem and how can it be solved? Thanks for your help.
ui.NewEntry returns *Entry, therefore your slice should be declared as:
var entlist []*ui.Entry
interface I {
a: number;
}
interface II extends I {
b: number;
}
function f(arg: I) : void {
// do something with arg without trimming the extra properties (logical error)
console.log(arg);
}
const obj: II = { a:4, b:3 };
f(obj);
What I want to do is to make function f to accept only objects of type I and not type II or any other derived interface
Difficult because of the way typescript works. What you can do is add a type field to the base, which a derived interface would override. Then to limit a function to only accept the base explicitly:
interface IFoo<T extends string = "foo"> {
type: T;
}
interface IBar extends IFoo<"bar"> {
}
function ray(baseOnly: IFoo<"foo">) {
}
let foo: IFoo = { type: "foo" };
let bar: IBar = { type: "bar" };
ray(foo); // OK!
ray(bar); // error
and the output error:
[ts]
Argument of type 'IBar' is not assignable to parameter of type 'IFoo<"foo">'.
Types of property 'type' are incompatible.
Type '"bar"' is not assignable to type '"foo"'.
You cannot achieve this in Typescript, in general, in most languages you cannot make such a constraint. One principle of object oriented programming is that you can pass a derived class where a base class is expected. You can perform a runtime check and if you find members that you don't expect, you can throw an error. But the compiler will not help you achieve this.
This works for me (on ts 3.3 anyway):
// Checks that B is a subset of A (no extra properties)
type Subset<A extends {}, B extends {}> = {
[P in keyof B]: P extends keyof A ? (B[P] extends A[P] | undefined ? A[P] : never) : never;
}
// Type for function arguments
type Strict<A extends {}, B extends {}> = Subset<A, B> & Subset<B, A>;
// E.g.
type BaseOptions = { a: string, b: number }
const strict = <T extends Strict<BaseOptions, T>>(options: T) => { }
strict({ a: "hi", b: 4 }) //Fine
strict({ a: 5, b: 4 }) //Error
strict({ a: "o", b: "hello" }) //Error
strict({ a: "o" }) //Error
strict({ b: 4 }) //Error
strict({ a: "o", b: 4, c: 5 }) //Error
// Type for variable declarations
type Exact<A extends {}> = Subset<A, A>;
// E.g.
const options0: Exact<BaseOptions> = { a: "hi", b: 4 } //Fine
const options1: Exact<BaseOptions> = { a: 5, b: 4 } //Error
const options2: Exact<BaseOptions> = { a: "o", b: "hello" } //Error
const options3: Exact<BaseOptions> = { a: "o" } //Error
const options4: Exact<BaseOptions> = { b: 4 } //Error
const options5: Exact<BaseOptions> = { a: "o", b: 4, c: 5 } //Error
// Beware of using Exact for arguments:
// For inline arguments it seems to work correctly:
exact({ a: "o", b: 4, c: 5 }) //Error
strict({ a: "o", b: 4, c: 5 }) //Error
// But it doesn't work for arguments coming from variables:
const options6 = { a: "o", b: 4, c: 5 }
exact(options6) // Fine -- Should be error
strict(options6) //Error -- Is correctly error
You can see more detail in my comment here.
So applied to your example:
interface I { a: number; }
interface II extends I { b: number; }
function f<T extends Strict<I, T>>(arg: T): void {
// do something with arg without trimming the extra properties (logical error)
console.log(arg);
}
const obj1: I = { a: 4 };
const obj2: II = { a: 4, b: 3 };
f(obj1); // Fine
f(obj2); // Error
Another possibility is to give up on interfaces and use classes with private properties and private constructors. These discourage extension:
export class I {
private clazz: 'I'; // private field
private constructor(public a: number) {
Object.seal(this); // if you really don't want extra properties at runtime
}
public static make(a: number): I {
return new I(a); // can only call new inside the class
}
}
let i = I.make(3);
f(i); // okay
You can't create an I as an object literal:
i = { a: 2 }; // error, isn't an I
f({a: 2}); // error, isn't an I
You can't subclass it:
class II extends I { // error, I has a private constructor
b: number;
}
You can extend it via interface:
interface III extends I {
b: number;
}
declare let iii: III;
and you can call the function on the extended interface
f(iii);
but you still can't create one with an object literal
iii = { a: 1, b: 2 }; // error
or with destructuring (which creates a new object also),
iii = { ...I.make(1), b: 2 };
, so this is at least somewhat safer than using interfaces.
There are ways around this for crafty developers. You can get TypeScript to make a subclass via Object.assign(), but if you use Object.seal() in the constructor of I you can at least get an error at runtime:
iii = Object.assign(i, { b: 17 }); // no error at compile time, error at runtime
And you can always silence the type system with any, (although again, you can use an instanceof guard inside f() to cause an error at runtime).
iii = { a: 1, b: 2 } as any; // no error
f(iii); // no error at compile time, maybe error if f() uses instanceof
Hope that helps; good luck!
I have problem with NSProgress. The problem is that NSProgressIndicator is not updating during the process and showing only a small completed portion at the end of process. The localizedDescription is also showing only at the end of the process, but as 100% completed.
So, I have a class with one method findRepeatsWithProgressReporting using NSProgress
class TestProgress: NSObject, ProgressReporting
{
let progress: Progress
override init()
{
progress = Progress()
super.init()
}
func findRepeatsWithProgressReporting(stringToSearch: String, minimalLength: Int, maximalLength: Int) -> [String]
{
var arrayOfRepeats = [String]()
progress.totalUnitCount = Int64((minimalLength...maximalLength).count)
for i in minimalLength...maximalLength
{
let arrayOfStrings = stringToSearch.chopString(stringOut: stringToSearch, length: i)
let arrayOfUniqueStrings = Array(Set(arrayOfStrings))
for each in arrayOfUniqueStrings
{
let arrayOfNSRanges = stringToSearch.searchForNSRangesOfStringInString(stringOut: stringToSearch, stringIn: each)
var positions = String()
if arrayOfNSRanges.count > 1
{
for each1 in arrayOfNSRanges
{
let repeatStart = String(each1.location + 1)
let repeatEnd = String(each1.location + each1.length)
positions += "(" + repeatStart + "-" + repeatEnd + ")"
}
let stringToShow = each + " " + positions
arrayOfRepeats.append(stringToShow)
}
}
progress.completedUnitCount += 1
}
return arrayOfRepeats
}
}
Then, in myVewContrloler I have parentProgress repeatsProgress having totalUnitCount: 10 and have added the task of the method findRepeatsWithProgressReporting as childProgress to the parentProgress repeatsProgress using repeatsProgress.becomeCurrent(withPendingUnitCount: 10).
private var progressObservationContext = 0
class myVewContrloler: NSViewController
{
...
var testProgress = TestProgress ()
var repeatsProgress = Progress()
#IBOutlet weak var repeatsSearchProgressBar: NSProgressIndicator!
#IBOutlet weak var repeatsPercentText: NSTextField!
#IBOutlet weak var minimalLength: NSTextField!
#IBOutlet weak var maximalLength: NSTextField!
#IBOutlet var foundRepeats: NSTextView!
#IBAction func actionFindRepeats(_ sender: AnyObject)
{
repeatsProgress = Progress(totalUnitCount: 10)
let options : NSKeyValueObservingOptions = [.new, .old, .initial, .prior]
repeatsProgress.addObserver(self, forKeyPath: "fractionCompleted", options: options, context: &progressObservationContext)
repeatsProgress.addObserver(self, forKeyPath: "localizedDescription", options: options, context: &progressObservationContext)
var arrayOfRepeats = [String]()
repeatsProgress.becomeCurrent(withPendingUnitCount: 10)
arrayOfRepeats = testProgress.findRepeatsWithProgressReporting(stringToSearch: stringToSearch, minimalLength: minimalLength.integerValue, maximalLength: maximalLength.integerValue)
...
repeatsProgress.removeObserver(self, forKeyPath: "fractionCompleted")
repeatsProgress.removeObserver(self, forKeyPath: "localizedDescription")
repeatsProgress.resignCurrent()
}
}
The last part is for KVO :
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{
guard context == &progressObservationContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if keyPath == "fractionCompleted"
{
OperationQueue.main.addOperation{
let progress = object as! Progress
self.repeatsSearchProgressBar.doubleValue = progress.fractionCompleted
self.repeatsPercentText.stringValue = progress.localizedDescription
}
}
}
I have added
print("Observed Something")
inside of the
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{ ...
and what I see is two times printing the "Observed Something"immediately after start and six times at the end, no printing in between (as it expected to be for the updating process). What can be the reason ?
This seems like a concurrency problem. Since func actionFindRepeats(_ sender: AnyObject) is running in the main thread, it's concurring with the UI updates, which affects the NSProgressIndicator directly.
See the last example of that answer for more details about that:
https://stackoverflow.com/a/35810608/4370893
You can try adding all the content of your actionFindRepeats function into that block and see if it works:
DispatchQueue.global().async {
// qos' default value is ´DispatchQoS.QoSClass.default`
}
Reference for that block:
https://stackoverflow.com/a/37806522/4370893