I'm trying to change the color of a panel on Lazarus on mouse hover.
I try run this code on Lazarus:
unit test;
{$mode objfpc}{$H+}
interface
uses
[...]
type
{ Tvendas_menu }
Tvendas_menu = class(TForm)
[...]
procedure StartMouseEnter(Sender: TObject);
[...]
private
{ private declarations }
public
{ public declarations }
end;
var
[...]
implementation
[...]
procedure Tvendas_menu.StartMouseEnter(Sender: TObject);
begin
Start.Color := $00E7E7E7;
end;
[...]
But when compiling the program show the following error code:
Error: Identifier not found "Start"
I'm sure that "Start" is the name of the panel on Object Inspector and .lfm file.
I try to change "Start" to another name but the error still occurs.
Thanks!
When you add controls to the form they automagically get added under the form class, in your case they would appear under Tvendas_menu = class(TForm).
One possibility of the error could be because the line Start is missing, you should have something like:
type
Tvendas_menu = class(TForm)
Start: TPanel;
private
{ Private declarations }
public
{ Public declarations }
end;
To resolve this, try adding the line Start: TPanel; like above if it is not present.
One other option you have is to view the form in text view (.lfm for Lazarus and .dfm for Delphi) and find the reference block for Start, it may look something like:
object Start: TPanel
Left = 152
Top = 248
Width = 185
Height = 41
Caption = 'Start'
TabOrder = 1
end
Delete that and then return back to Form view.
Then you can try adding a new panel to the form and naming it Start, then you just need to link your event handlers back to the new control.
As a side tip, naming a control Start is not really very useful, maybe think of a better named identifier such as panStart.
Related
The following Delphi program calls method upon nil reference and runs fine.
program Project1;
{$APPTYPE CONSOLE}
type
TX = class
function Str: string;
end;
function TX.Str: string;
begin
if Self = nil then begin
Result := 'nil'
end else begin
Result := 'not nil'
end;
end;
begin
Writeln(TX(nil).Str);
Readln;
end.
However, in a structurally similar C# program, System.NullReferenceException will be raised, which seems to be the right thing to do.
namespace ConsoleApplication1
{
class TX
{
public string Str()
{
if (this == null) { return "null"; }
return "not null";
}
}
class Program
{
static void Main(string[] args)
{
System.Console.WriteLine(((TX)null).Str());
System.Console.ReadLine();
}
}
}
Because TObject.Free uses such style, it seems to be "supported" to call method on nil reference in Delphi. Is this true ? (Let's suppose that in the if Self = nil branch, no instance field will be accessed.)
It is reasonable to call a method on a nil reference, subject to the following rules:
The method must not be virtual or dynamic. That is because virtual or dynamic methods are bound using the runtime type of the reference. And if the reference is nil then there is no runtime type. By way of contrast, non-virtual, non-dynamic methods are bound at compile time.
You are allowed to read the value of Self, for instance to compare it against nil.
In case Self is nil, then you must not refer to any instance variables.
I have this (defined in delphi source code):
TCanvasTextureMaterial = class(TCustomMaterial)
private
[Weak] FTexture: TTexture;
procedure SetTexture(const Value: TTexture);
protected
public
property Texture: TTexture read FTexture write SetTexture;
end;
how to override the setter SetTexture in descendant class?
In short, you can't.
The setter is declared as private and thus is not accessible to descendants. But even if it were accessible, it is not declared as virtual so it can't be override'n anyway.
The only thing a descendant could do in this case is (re)declare its own property with its own setter (it could even reuse the same Texture property name), eg:
type
TMyCanvasTextureMaterial = class(TCanvasTextureMaterial)
private
function GetMyTexture: TTexture;
procedure SetMyTexture(const Value: TTexture);
public
property Texture: TTexture read GetTexture write SetMyTexture;
end;
But, accessing the Texture property via a TCanvasTextureMaterial pointer will not call the descendant's setter, even if it does use the same property name:
var
TM: TCanvasTextureMaterial;
begin
TM := ...; // any TMyCanvasTextureMaterial object
// reading from TM.Texture returns TCanvasTextureMaterial.FTexture,
// it does not call TMyCanvasTextureMaterial.GetMyTexture()
// assigning to TM.Texture calls TCanvasTextureMaterial.SetTexture(),
// it does not call TMyCanvasTextureMaterial.SetMyTexture()
end;
well today i was re-writing some olds stuff here and got myself into a problem that i don't know the answer.
i created the following attribute:
Enumeration<T> = class(TCustomAttribute)
strict private
{ Private declarations }
FValues : TList<T>;
public
{ Public declarations }
constructor Create(const AValues : array of T);
destructor Destroy(); override;
public
{ Public declarations }
property Values : TList<T> read FValues;
end;
with that in mind, i can use this attribute just fine in the following class for example:
[Entity('tablename')]
TUser = class(TEntity)
strict private
[Column('idcolumnname')]
[PrimaryKey(True)]
Fid : TInteger;
[Column('typecolumnname')]
[Enumeration<string>(['A', 'B', 'C', 'D', '...'])]
Ftype: TEnumeration<string>;
end;
it is great that it worked but idk, it seems to me that this should'nt work, couse in my ignorance, delphi attributes expect only constant types and im not only using array as a paremeter but a generic one.
moving foward, i made this attribute:
Association = class(TCustomAttribute)
strict private
{ Private declarations }
FMasterKeys : TList<string>;
FDetailKeys : TList<string>;
public
{ Public declarations }
constructor Create(const AMasterKeys, ADetailKeys : array of string);
destructor Destroy(); override;
public
{ Public declarations }
property MasterKeys : TList<string> read FMasterKeys;
property DetailKeys : TList<string> read FDetailKeys;
end;
and tried to use on this class:
[Entity('tablename')]
TSuperUser = class(TEntity)
strict private
[Association(['masterkey'], ['detailkey'])]
Fuser : TAssociation<TUser>;
end;
i got a error [DCC Error] E2026 Constant expression expected.
ok, so in resume i just dont know whats happening why i can use a array of T as a attribute parameter and not a array of string for instance.
thx for any help in advance
Check your compiler warnings. It should say W1025 Unsupported language feature: 'custom attribute' for your "compiling code". So what you though compiles did in fact not. It just did not raise an error.
This is usually the case when an attribute class cannot be found because fact you cannot have generic attributes. And is still the case in XE7.
Bottom line: Even if it did compile your executable will not contain that attribute.
Ok, I have been using the excellent Delphi-Mocks Framework and I just encountered a problem. Let´s suppose I have the following interfaces:
IDepartment = Interface
['{F4915950-8F32-4944-A3B6-8E08F6C38ECC}']
function getID() : Integer;
function getName() : String;
property ID: Integer read getID;
property Name: String read getName;
end;
ISale = Interface
['{F4915950-8F32-4944-A3B6-8E08F6C38E77}']
function getAmmount() : Currency;
function getDepartment() : IDepartment;
property Ammount: Currency read getAmmount;
property Department : IDepartment getDepartment;
end;
Now, I am trying to test the Sale interface using DUnit and the Delphi-Mocks, and use it as follows:
procedure TMyTest.Test_Sale_HasDepartment;
var
mckDepartment : TMock<IDeparment>;
mckSale : TMock<ISale>;
begin
mckDepartment := TMock<IDepartment>.Create;
mckDepartment.Setup.WillReturn('My Department').When.Name;
mckDepartment.Setup.WillReturn(1).When.ID;
// Create a sale Mock
mckSale := TMock<ISale>.Create;
mckSale.Setup.WillReturn(100).When.Ammount;
//** Here´s there is where I don´t know how to add a "child mock"**
mckSale.Setup.WillReturn(TValue.From<IDepartment>(mckDepartment)).When.Department;
// What I am trying to get is the following:
WriteLn(mckSale.Instance.Department.Name); // Should return "My Department" but fails with an AV.
end;
So my question is: How can I add a child mock to an existing mocked Interface and call its methods and properties?
Thanks!
P.S. I am using Delphi XE2.
mckSale.Setup.WillReturnDefault('getDepartment', TValue.From(mckDepartment));
I have a TPageControl with a number of TTabSheets that contain TForms (or possibly TFrames, but TForms for now).
When a tab comes into view I would like the TForm or TFrame to be notified it has come to the front. I can't find anything that does that.
I know I can get the Active TTabSheet in the OnChange event, so I tried to add this class to the TForm:
struct iTab
{
virtual void DoIt( void ) = 0;
};
with the this in the OnChange:
ICPTab *tab = dynamic_cast<ICPTab *>( sheet->Controls[ 0 ] );
Thinking I could use RTTI to get the iTab pointer and call DoIt() from the
And I get the warning:
[BCC32 Warning] Unit1.h(18): W8130 Interface 'IPTab' does not derive from IUnknown. (Interfaces should derive from IUnknown)
[BCC32 Warning] MainWindow.cpp(612): W8131 Casting Delphi style class 'TControl' to an interface. Use 'System::interface_cast<ICPTab>(cls)' instead
I am not interested in getting all of IUnknown just so that the form can use an interface.
I can get the TFrame or TForm pointer using:
TForm *tab = dynamic_cast<TForm *>( sheet->Controls[ 0 ] );
but can't call a non TForm method with this pointer. Would it be ok to call the Activate() method?
So how do I notify the TForm or TFrame that it is now showing?
You have to derive iTab from IUnknown (or IInterface) or order to use it as an interface correctly. The compiler warning even hints that you can use interface_cast to extract an interface from a Delphi-style (aka TObject-derived) object. Alternatively use TObject::GetInterface() instead.
Otherwise, if you just want to call methods of your custom TForm class, then just type-cast the child control pointer from your TTabSheet to your actual TForm-derived class:
TMyForm *tab = dynamic_cast<TMyForm *>( sheet->Controls[ 0 ] );
if( tab != NULL ) tab->DoSomething();
Or:
static_cast<TMyForm *>( sheet->Controls[ 0 ] )->DoSomething();
I went with the following code:
void __fastcall TgMainWindow::mPageControlChange( TObject* Sender )
{
NOT_USED( Sender );
TTabSheet* sheet = mPageControl->ActivePage;
if ( sheet->ControlCount > 0 )
{
// form or frame, we will attempt to call the OnActivate method
TForm* form = dynamic_cast<TForm *>( sheet->Controls[ 0 ] );
if ( form == NULL )
{
ShowMessageDlg( this, L"Programming Error: Initial child on tabsheet must be a TForm", mtError, TMsgDlgButtons( ) << mbOK );
}
else
{
if ( form->OnActivate != NULL )
{
form->OnActivate( this );
}
else
{
ShowMessageDlg( this, L"Programming Error: From must have an OnActivate event", mtError, TMsgDlgButtons( ) << mbOK );
}
}
}
}
Since a form on a tabsheet never has its OnActivate method called, this works quite well.
note: the method sample is not complete, there is no call to OnDeactivate