jerous86 / nimqt

Qt bindings for nim
GNU General Public License v2.0
93 stars 6 forks source link

How to override inherited object's constructor? #8

Closed matkuki closed 1 year ago

matkuki commented 1 year ago

Hi, is it even possible?

inheritQObject(CustomTabWidget, QTabWidget):
    ???
jerous86 commented 1 year ago

That's not possible. But not sure if that's something that should be really supported? Could you give some examples how you would use it?

matkuki commented 1 year ago

I apologize, I'm coming from the Qt/PyQt side of things and there when overriding I usually initialize some new class attributes in the constructor, like for example Qt:

class MyTabs: public QTabWidget
{
    Q_OBJECT

public:
    MyTabs(QWidget* parent=0, int in_mvalue=-1) : QTabWidget(parent) {
        mvalue = in_mvalue;
    }

private:
    int mvalue;
};

... or in PyQt:

class MyTabs(PyQt6.QtWidgets.QTabWidget):
    mvalue = None

    def __init__(self, parent, in_mvalue):
        super().__init__(parent)
        self.mvalue  = in_mvalue

What is the nimqt idiomatic way of adding attributes and initialization to an inherited type? What would be the the nimqt of the above example?

jerous86 commented 1 year ago

In nim I don't think there's this concept of a constructor or nim, it's all just procs/funcs. So you could define

proc newMyTabs(in_mvalue = -1): ptr MyTabs =
    result=newMyTabs() # This is just the "constructor" that's generated by inheritQObject
    result.mvalue=in_mvalue

creating a new custom constructor.

However, currently the use of this is quite limited, as member variables are not supported yet by inheritQObject, it's also on my TODO list :)

matkuki commented 1 year ago

However, currently the use of this is quite limited, as member variables are not supported yet by inheritQObject, it's also on my TODO list :)

Good to know, thanks 👍👍

jerous86 commented 1 year ago

I just added some simple support for member variables :)

There's no syntax to set the initial value, so you'll have to do that manually.

matkuki commented 1 year ago

Excellent, thank you 👍👍👍

matkuki commented 1 year ago

Just tried installing the main branch and used it with this code:


#[
    Main window testing
]#

import os
import strformat
import std/enumerate

import nimqt
import nimqt / [
    qlabel,
    qpushbutton,
    qboxlayout,
    qtabwidget,
    qmainwindow
]

nimqt.init

inheritQObject(GuiHandler, QObject):
    slot_decl on_helloWorld_clicked()

proc on_helloWorld_clicked(this: ptr GuiHandler) =
    let sender = cast[ptr QPushButton](this.get_sender())
    sender.setText(Q "Hello world!")

## Custom tab-widget
inheritQObject(CustomTabWidget, QTabWidget):
    discard

proc main() =
    let
        app = newQApplication(os.commandLineParams())
        guiHandler: ptr GuiHandler = newGuiHandler()
        main_window = newQMainWindow()
        main_widget = newQWidget()
        main_layout = newQVBoxLayout(parent=main_widget)
        main_stylesheet = Q fmt"""
QMainmain_windowdow {{
    border: none;
    margin: 0px;
    padding: 0px;
    spacing: 0px;
}}

QTabBar {{
    border: none;
    margin: 0px;
    padding: 0px;
    spacing: 0px;
}}
QTabWidget {{
    border: none;
    margin: 0px;
    padding: 0px;
    spacing: 0px;
}}

QPushButton {{
    border: 1px solid black;
    margin: 0px;
    padding: 0px;
    spacing: 0px;
}}
"""
        tab_widget = newCustomTabWidget(parent=main_widget)
        stylesheet: QString = newQString("background: red;")
        buttons = [
            newQPushButton(Q "Click me 0!!"),
            newQPushButton(Q "Click me 1!!"),
            newQPushButton(Q "Click me 2!!"),
        ]

    main_window.setWindowTitle(Q "Nim app")
    main_window.setWindowIcon(newQIcon(Q "../resources/logo_nim.png"))

    main_layout.setSpacing(0)
    main_layout.setContentsMargins(0, 0, 0, 0)
    main_widget.setLayout(main_layout)
    main_widget.setStyleSheet(main_stylesheet)

    tab_widget.setMovable(true)
    main_layout.addWidget(tab_widget)

    for i,b in enumerate(buttons):
        if i == 1:
            b.setStyleSheet(stylesheet)
        b.connect(SIGNAL "clicked()", guiHandler, SLOT "on_helloWorld_clicked()")
        discard tab_widget.addTab(b, (Q fmt"TAB {i}"))

    main_window.setCentralWidget(main_widget)
    main_window.resize(640, 480)

    main_window.show()
    discard app.exec()

if isMainModule:
    os.setCurrentDir(os.getAppDir())
    main()

and now I get this error:

C:\Users\matic\.nimble\pkgs\nimqt-0.1\nimqt.nim(346, 11) inheritQobject
C:\Users\matic\.choosenim\toolchains\nim-1.6.10\lib\system\assertions.nim(38, 26) failedAssertImpl
C:\Users\matic\.choosenim\toolchains\nim-1.6.10\lib\system\assertions.nim(28, 11) raiseAssert
C:\Users\matic\.choosenim\toolchains\nim-1.6.10\lib\system\fatal.nim(54, 5) sysFatal
J:\Nim\nimqt\mainwindow_example\mainwindow_example.nim(30, 15) template/generic instantiation of `inheritQobject` from here
C:\Users\matic\.choosenim\toolchains\nim-1.6.10\lib\system\fatal.nim(54, 5) Error: unhandled exception: C:\Users\matic\.nimble\pkgs\nimqt-0.1\nimqt.nim(346, 21) `false` inheritQobject: Expected nnkCommand or nnkVarSection, but got nnkDiscardStmt [AssertionDefect]
stack trace: (most recent call last)
J:\Nim\nimqt\mainwindow_example\mainwindow_example_build.nims(86, 9)

This code worked with the previous version: image

jerous86 commented 1 year ago

Ah yes, I forgot to handle a discard statement. That should be fixed now in main!

matkuki commented 1 year ago

Thanks, it works now 👍👍

Although I had to change my inherited widget's initializer procedure signature from: tab_widget = newCustomTabWidget(parent=main_widget) to tab_widget = newCustomTabWidget()