Important: Please read the Qt Code of Conduct -

How to access Button in ui placed on other ui

  • I have a ui that is placed on a page in a StackedWidget (as class).
    How do I access buttons in this ui from the cpp of the main page of the StackedWidget?

    This works to access on current page: ui->pushButtonX
    What does not work and probably is written wrong: otherpage::ui->pushButtonY

  • @otherpage::ui@
    It should be then static public member. And it is not i guess...

    So if you need access members of other class, make this member public and don't forget to initialize this class(create instance), because UI will be created in class constructor with ui.(->)SetupUI etc...

    for example:

    class Widget1: public QWidget
    this->ui 0 new Ui::Widget1;

    UI::Widget1 * ui;

    void Widget2::test()
    Widget1 * wdg = new Widget1();

    But it is wrong way to access ui elements of other widget... Right way is to create signals/slots connection between this 2 classes.

  • bq. But it is wrong way to access ui elements of other widget… Right way is to create signals/slots connection between this 2 classes.

    OK. I'll look into the right way first before doing it the wrong way.

  • Stuck here:

    in ui2.cpp
    @connect("ui1", SIGNAL(cursorLeft()),SLOT(cursorMoveLeft()));@

    how do I reference a signal emitted in the ui1?

  • I was reading lots of documentation and training material, but still could not figure how to do it the right way. The question in my post above remains open to me.
    Did it the dirty way for the moment and it works (needs to be finished for a demo in a couple of hours)

    • created public slots in ui2
    • made ui's public
    • included the headers of the other ui

    et voila

  • You should think of it like this:
    If anything outside of your class A cares about class A having a button, then your design is wrong. Anything outside of your class A, should only care about the API of class A itself. So, if clicking a button that is a member of class A needs to trigger some action outside of class A, than class A needs to expose that functionality by itself. In this case: class A needs to gain a signal triggerActionFoo() that interested classes outside of class A can connect to. That class A emits this signal in response to a click to button Foo, is of no concern to anything outside class A. That leaves you free to change the way the action is triggered from using a button to perhaps using a hyperlink, to name an example, and not need any changes outside of class A.

    In conclusion:

    • Add a signal to your class, and give it a proper name. That it: name the action, instead of calling it 'button1Clicked'.
    • Connect your button's clicked signal to this signal (yes, you can connect a signal to another signal)
    • Connect your outside code to the new signal you created on your class.

    Now, your m_ui can stay private as it should be.

  • Andre,

    Thats exactly what I did! Created and emitted a signal ....
    What I could not get to work is this little peace of code I posted before: see the "ui1" in there ... what to write there?

  • The first argument for a connect call is the source object. Since the source object is now the class you created, it should be a pointer to that class.

  • Yeah, I know that ... since I read the documentation.
    Frankly, I seem to dumb to put in the right letters ... and could not build.

    Since this is for a temporary demo unit - that is loaded on a truck for the exhibition in 2 hours - I leave it that way right now and make it correct for the software in the release later.

    Thanks a lot for your support anyway.

  • Here’s an example how I acccessd a text widget from another class (from outside MainWindow class).
    From MainWindow, I pass a pointer to the widget I want to to update.
    In below example I pass a ref to a Textedit widget that I then use for “debug” output back to the Main window: (My texedit widget is named out_te in this example:)

    From MainWindow:
    @port_info_list = communicate.comsearch(ui->user_out_te);

    In class Communication:
    @QList<QSerialPortInfo> communicate::comsearch(QTextEdit* out_te) //<== Pass pointer to widget!
    QList<QSerialPortInfo> portlist; portlist = QSerialPortInfo::availablePorts(); out_te->append(“T E S T write from outside MainWindow!”); //<==
    return portlist;

    BTW, trying to reference MainWindow from my communications class with e.g. <ui.out_te> or <MainWindow.> (or derefereincing with ->) never worked for me even though I had in mainwindow.h
    public: Ui::MainWindow *ui;

    I know passing a ref like this is not exactly recommended in C++, but I’m new to Qt, live in the embedded world, plus I don't yet know yet how to add a signal / slot manually to send data back to the MainWindow text widget. Please do comment on this!

  • I recommend against the approach shown by CarlStenquist above. You end up with code that is much to tightly coupled. The Communications class has no business knowing about UI elements like a QTextEdit. Instead, it should just expose a list of ports (in this case) and signal changes to that list. What happens if you want the port list to appear in some other type of widget? Or you want to log it?

  • Let's not make a storm out of a breeze here. I did not want to introduce a schoolbook example, but be practical. I think your argument misses the target of solving a problem posed. My intention was to use the textwidget to feed debug strings to the GUI (the user). That's exaclty why I added the text widget.

    The Communications class deals only with protocol and needs to send information back to the user. I guess I could open up a new window, but I have no need at all for that.

    You wrote "What happens if you want the port list to appear in some other type of widget?" Your reasoning eludes me. If the MainWindow should for some reason need the port list it would ask the Commnunications class for it. This would be due to some user interaction with MainWindow.

  • I guess we're misunderstanding each other here.

    I do not claim that the Communications class should open its own window. Far from it! It should not deal with UI aspect at all. That also means that it should not deal with putting data in a QTextEdit.

    What I mean is that if MainWindow (or whatever other class) needs this information, it shoudl indeed ask the Communications class for it. But your choice for passing a QTextEdit to get that information is wrong IMHO. What happens if I want to change my main view to use an item view instead? Or put the ports in a combo box? The Communications class should use a more neutral API instead, and simply pass the data as list of port numbers or something like that. Whatever the caller does with that list (display in a QTextExit, put them in a QComboBox or logging them to a logfile) is not and should not be relevant to the Communications class.

  • Andre,
    Thanks. Yes, I do agree in theory and do understand your point.
    For this simple project though it is a very simple and efficient way to stream info to the user. Otherwise, I would have to write plenty of code in my Comm. class and in Main to ask for data from the Comm. class at predetermined points of time. That is alot of work to do, and I do not know exactly all I will need to output to user yet. Depends on the issues I run into. And then changing it later would means lots of rework I suspect...
    But again, in general I agree. Always make effort to not expose members to other classes.

Log in to reply