Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature that allows passing parameters when creating delphivcl objects #85

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

excript
Copy link

@excript excript commented Feb 21, 2024

Visual Error Messages

The components of "delphivcl" have a restriction on binding new symbols at runtime and their subsequent reading. For example, the following code snippet displays an error message on the application's interface:

bt = Button(self)
bt.aaa = 10

Initially, this problem could be addressed by modifying the library not to raise the "AttributeError" exception when binding or reading an unknown symbol, as shown below:

AttributeError('Error in getting property "aaa".\nError: Unknown attribute')

However, the absence of a symbol in an object should not result in a visual error message, as it provides no useful information to the end user and is also not internationalized.

A suggestion would be to reduce or completely eliminate the visual messages generated by "delphivcl," opting instead to notify the developer through the raising of exceptions.

A viable alternative would be to allow the developer to choose whether to display such messages during development, using an appropriate flag.

When examining the Pascal code of the "WrapDelphi.pas" unit, we can observe the following snippet:

if not Assigned(Result) then
    with GetPythonEngine do
        PyErr_SetObject (PyExc_AttributeError^,
          PyUnicodeFromString(Format(rs_ErrAttrGet, [FRttiMember.Name, LOutMsg])));

In this snippet, it is checked whether a symbol is present, and if its name is not found, an exception is thrown. This logic is repeated at least 12 times in the "WrapDelphi.pas" unit.

Additionally, error messages are defined as constants in the unit:

rs_ErrAttrGet = 'Error in getting property "%s".'#$A'Error: %s';
rs_ErrAttrSetr = 'Error in setting property %s'#$A'Error: %s';

ATTRIBUTE DEFINITION DURING CREATION

By default, creating an object in the delphivcl environment does not allow the definition of properties during instantiation.

Properties can be defined using dot notation (obj.Caption) or, less elegantly, through the SetProps() function.

When a new object is instantiated in Python, the __init__(self, *args, **kwargs): method is called, allowing parameter passing.

Below, a simplified solution is presented that allows the definition of properties during object creation and enables the association and reading of new symbols in objects from the delphivcl library.

comps = [
    delphivcl.Button,
    delphivcl.Label,
    delphivcl.Edit,
]

def main(self, *args, **kwargs):
    for key, value in kwargs.items():
        setattr(self, key, value)

def change_types():
    for c in comps:
        newc = type(c.__name__,
                    (c,),
                    {"__init__": main})

        setattr(delphivcl, c.__name__, newc)

change_types()

Now, the three objects listed in comps can define properties during instantiation and are also capable of associating and reading symbols.

It is recommended to execute the entire code at the end of the delphivcl library import, in the __init__.py file.

@excript
Copy link
Author

excript commented Feb 21, 2024

Now, it is possible to create components by passing parameters directly through the constructor.

self.ed = LabeledEdit(self, Parent=self, Text="10", Left=100, Top=150, Width=300, Height=300)
self.bt = Button(self, Parent=self, Caption="Button 1", Left=200, Top=190, Width=100, Height=35, OnClick=self.on_click)

Full code example:

import delphivclhack

from delphivcl import Form, FreeConsole, Application, PageControl, LabeledEdit, Edit, Button

class AppForm(Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.ed = LabeledEdit(self, Parent=self, Text="10", Left=100, Top=150, Width=300, Height=300, OnChange=self.on_change)
        self.bt = Button(self, Parent=self, Caption="Button 1", Left=200, Top=190, Width=100, Height=35, OnClick=self.on_click)

    def on_click(self, event):
        self.ed.aaa = 10
        print(self.ed_txt.aaa)


def main():
    Application.Initialize()
    Application.Title = "Teste"
    app = AppForm(Application)
    app.Show()
    FreeConsole()
    Application.Run()
    Application.Minimize()
    app.Destroy()

main()

@lmbelo lmbelo self-assigned this Feb 21, 2024
@lmbelo lmbelo added the enhancement New feature or request label Feb 21, 2024
@lmbelo
Copy link
Member

lmbelo commented Feb 21, 2024

@excript,

this is very useful and sight for sore eyes. I'm only wondering if we should take it to the Delphi code directly. We also need to replicate this behavior to the delphifmx library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants