Although I have read the answers to this question
QT/C++ - Accessing MainWindow UI from a different class
and searched the whole www for quite some time - I don't get it working.
I was given the task to recreate an applications UI using QT Designer. Unfortunately there was already some UI spread all over several classes (the team then came across the idea, that using QT but not using the Designer however "handcoding" the UI seems to make little sense)
So now my job is to untangle the open ends, create a GUI (done that) find every possible signal and slot and put it all together to look nice and clean.
So much for the theoretical part.
Addition: I have very little experience in C++ and I seem to be getting nowhere searching for answers and don't have the time to read whole books until tomorrow, otherwise I wouldn't ask.
I am kind of going nuts about two things:
A) My mainwindow.cpp, mainwindow.h and mainwindow.ui need to be linked into other files e.g. the previewwidget.cpp...
the previewwidget.cpp had a lot of code like:
buttonLayout->addWidget(fpsSpinBox, 0, Qt::AlignCenter);
buttonLayout->addWidget(playButton, 0, Qt::AlignCenter);
buttonLayout->addWidget(backwardButton, 0, Qt::AlignCenter);
apparently I replaced it by creating the corresponding buttons in Designer.
now in the same file theres the connect SIGNAL SLOT entries (I added the "ui->")
connect(ui->playButton, SIGNAL(clicked()), this, SIGNAL(playButtonClicked()));
connect(ui->stopButton, SIGNAL(clicked()), this, SIGNAL(stopButtonClicked()));
connect(ui->forwardButton, SIGNAL(clicked()), this, SIGNAL(forwardButtonClicked()));
but the compiler keeps telling me:
\preview\previewwidget.cpp:77: Error:'ui' was not declared in this scope
I put the ui_mainwindow.h into the header but that wasn't the solution either.
B) This Question is probably related very closely to the first one: since the Designer strickly keeps model/view/controll apart I need to rewrite the signals and slots to match the new UI - has anyone got a good tutorial or any hints for me how to do this fast and uncomplicated?
Any help would be greatly appreciated.
Let's assume you have a class called MyWidget and a corresponding ui file MyWidget.ui. In order to use it in your class I would do the following:
In the MyWidget.ui set a value to the objectName. It's the first property in the Property Editor if you open the file with the Designer. I would name it MyWidget
In the MyWidget.h you have to do the following:
Declare a namespace for the ui object and forward declare it.
Add as member variable (private) a pointer to the ui object.
Sample header file follows:
#ifndef MY_WIDGET_H_
#define MY_WIDGET_H_
#include <QWidget>
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget* parent = NULL);
~MyWidget();
// Add other class functions
private:
Ui::MyWidget ui;
}
#endif // MY_WIDGET_H_
In the MyWidget.cpp
Include the automatically generated ui_MyWidget.h
Create a new ui object in the constructor
Call the setupUi function in the constructor
Delete the ui in the destructor
Sample code:
#include "MyWidget.h"
#include "ui_MyWidget.h"
MyWidget::MyWidget(QWidget *parent)
:QWidget(parent), ui(new Ui::MyWidget)
{
ui->setupUi(this);
}
MyWidget::~MyWidget()
{
delete ui;
}
Now you are ready to use the ui throughout your class. For example if you have a spin box called spinBox1 you can take its value using
int val = ui->spinBox1->value();
.ui Signals and Slots
I would advise you to use QtDesigner in order to make the connections between ui widgets and slots. Check this link for more details.
If you want to connect a widget with a custom slot you can again do it using the designer.
Switch to Edit Signals/Slots mode (F4)
Drag and drop from the widget which it to emit the signal, to the widget which is to receive the signal.
A Configure Connection dialog appears, showing the signals for the emitting widget, and the slots for the receiving widget. Click
Edit... below the slots column on the right.
A Signals/Slots of ReceivingWidget dialog appears. In here its is possible to click the plus icon beneath slots to add a new slot of
any name.
You can then go back and connect to your new slot in the Configure Connection dialog, or indeed in the Signal/Slot Editor
dockwidget back in the main window.
Related
I want to understand if the following sequence is possible? If yes, how can we achieve the same?
MainWindow Qt GUI has a QPushButton
While we click on the QPushButton, it must open another Qt GUI Window (a different class, say 'DialogClass')
In the newly opened Qt GUI Window we have a QLineEdit and QPushButton
While we enter data in the QLineEdit and click on the QPushButton (of the DialogClass) the MainWindow class should receive the data entered in QLineEdit
Any help on this item will be appreciated. Thanks in advance!
Qt foresees its signals and slots approach for such purposes.
The QPushButton of your class offers a signal clicked which you connect to a custom (self-written) slot of your dialog. The dialog's slot then should read the contents of the QLineEdit and publish these on the dialogs own (custom) signal, which is connected to a (custom) slot of your main window, which then can process the value originally contained in the line edit.
Details will resemble pretty much the example of Qt's signals and slots documentation, so I won't be more explicit about.
I am confused about some Qt architecture.
When I am designing the GUI in Qt Designer it is easy to put the elements in a layout (Grid, Box, what ever) and create a slot to connect elements (e.g. buttons) with a certain and action not much code in .cpp file.
In the related .cpp file I can access theses elements via ui->element->do_something even from different functions within the class;
When not using the designer, instead creating the whole GUI stuff within the .cpp (adding element objects, add those objects to a layout, creating a slot, etc...) I cannot access my e.g. Button like ui->Button->do_something.
I am stuck at ui->Layout->functions from layout and cannot access the single elements and their functions like ui->textEdit->text(); or like ui->Layout->textEdit->text() from other functions within the class.
So how can I access those elements?
I am afraid I am missing an important point of Qt's architecture here or something else.
When you use designer, an "Ui" file is auto-generated with the code of your layout, then you access through the Ui::Mainwindow which you can see auto-generated in your QMainWindow class.
You can see in the default constructor:
QMainWindow(parent), ui(new Ui::MainWindow)
So each component defined in the gui file is accessible through ui::nameofyourcomponent.
If you write the code manually you don't have any "access point" to your element so you have to build your hierarchy exactly like each other part of your code and classes.
Edit: A little snippet to answer to his comment.
In you header you can declare:
private slots:
void doSomething();
private:
QPushButton* mybutton;
QLabel* mylabel;
in your Cpp:
connect(myButton, SIGNAL(clicked()), this, SLOT(doSomething) );
MyClass::doSomething()
{
mylabel->setText("hello button!");
}
Of course you can use the connect chaining directly the components through their signal and slot.
All of the objects the designer creates are public members of the ui object, that's why you can use them. To be able to use a manually created object, you have to store a pointer or reference to it somewhere.
I am new to QT and C++ and i have legacy qt-c++ code here which i cant get to work.
Probably its something about the lifetime of the calling objects but hey, but please tell me what i am missing.
In a QT .ui i have various Frames and Widgets containing Frames and Widgets containing a QVBoxLayout which we shall call "myLayout"
On click in the .ui file i use
myWidget = new mywidget(some params);
myLayout->addWidget(myWidget);
where myWidget is declared as mywidget *myWidget; in the header file
myWidget is a QWidget which internally adds a QVBoxLayout to itself and adds a QGraphicsView. Using the MouseReleaseEvent i emit a signal from the QWidget.
now when i try to connect the signal slot (which i do in cpp file from the ui)
connect(myWidget, SIGNAL(mySignal(QString)), this, SLOT(mySlot(QString)));
the signals never catch the slot. the slot is public, the signal isnt.
What did i do wrong? Can somebody help. Feel free to ask further questions since i dont really know whats important in c++ questions;)
edit:
the signal gets emitted by QGraphicsObjects which themselfs connect to a slot in the QGraphicsView. This Slot is called and debuggable. at the end of the Routine an emit mySignal("..."); is called.
Maybe you forgot to add Q_OBJECT macro in your widget declaration. Qt documentation: http://doc.qt.io/qt-5/qobject.html#Q_OBJECT
I am new to Qt GUI programming and come from a .NET/Winforms background as far as GUI development goes. I am using the Qt Creator IDE.
How can I handle a button press event in Qt to do something like the following:
if (button.clicked = true)
{
startProgram();
}
Also, how would I browse for a configuration file which would populate values into all of my line edit textboxes when opened? I am programming this in C++.
EDIT: I am taking a console app that someone else wrote and building a GUI around it. I want to access one of the functions in there from a button click event. However, I can't figure out how to get the functions of the original app to be in scope of the GUI which I have created when I try to use SIGNALS and SLOTS.
A simple example could be something like this. Say you have a class like ProgramStarter:
#include <QObject>
class ProgramStarter : public QObject {
Q_OBJECT
public slots:
void startProgram() {
//Do stuff
}
};
and something like this where ProgramStarter is used:
#include <QtGui/QApplication>
#include <QPushButton>
#include <QObject>
#include "programstarter.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPushButton *testButton = new QPushButton("Push me");
testButton->resize(100, 40);
testButton->show();
ProgramStarter *program = new ProgramStarter;
QObject::connect(testButton, SIGNAL(clicked()), program, SLOT(startProgram()));
return app.exec();
}
Qt uses signals and slots to communicate between objects. The core idea is that signals are emitted when events occur and these signals can be connected to slots. In this case the button emits a clicked() signal when the button is pressed and the clicked() signal is connected to the startProgram() slot. So when the button is pressed, startProgram() is called.
Qt has a meta-object system for enabling the use of signals and slots, among other things. This is the reason why ProgramStarter inherits QObject and why the Q_OBJECT macro is in the header. I highly suggest reading this if you want to understand how signals and slots and the meta-object system work in Qt: http://doc.qt.io/qt-5/signalsandslots.html
It's a little long to explain but you connect the signal from the button to the slot with the function.
connect(button, SIGNAL(triggered()), this, SLOT(doSomething()));
You really need to read and understand signals and slots before trying to write code
edit: You are trying to call functions in a compiled separate running program?
Are you confusing Qt Signals with C/Unix signals? You could start the separate app from within your Qt app, get its PID and then send it a 'c' signal.
Or if you have the source of the app you could include it's code into your Qt app and then call any of the functions by simply wrapping them with a Qt slot handler.
In order to access the functions defined in the console application, you need to include the headers (.h/.hpp) that declare these functions, and link their implementation. I you have the source code of the implementations (.cpp), you need to add them to the sources to be compiled (they will be compiled in object files (.o) that will be linked in the final executable). If the console application is a front-end to a set of functions defined in a library (.lib, .a), you need to link this library.
After that, you can use Qt's signal/slot mechanism to connect the "button clicked" signal to a slot calling the function you want to execute, as described in other answers.
It seems like your problem is not really to do with Qt or GUI programming at all, but rather a general design issue. Others have told you how to be notified when the button is pressed - it's up to you to hook that notification up to whatever code you want to call. Some possibilities:
If you just need to call a function then include the appropriate header file and call it.
If you have an object you want to call a method on, then you will need to provide a reference to that object to the class which receives the notification.
If your console app is a separate program, you can use QProcess to launch and communicate with it.
I guess your problem is that you cannot call the console app's function, because it hasn't been defined to be a slot. So here is how you might do it.
Let's assume you have a console app class which might look like this:
class ConsoleApp
{
public:
void run()
{
// Code which you want to trigger by a button in your UI.
}
}
Then we implement a Qt based wrapper class which inherits from QObject class and, hence, is able to send and receive signals. This class simply provides a custom slot which delegates execution to the ConsoleApp class.
class ConsoleAppWrapper : public QObject
{
Q_OBJECT
public slots:
void startProgram()
{
m_consoleApp.run();
}
private:
ConsoleApp m_consoleApp;
}
Ok, and now we want a button which, when pressed, will trigger a call of the 'run()' method.
int main(int argc, const char** argv)
{
QApplication app(argc, argv);
// Define wrapper for console app.
ConsoleAppWrapper wrapper;
// Define button and connect its 'clicked()' signal
// to the wrapper's 'startProgram()' slot.
QPushButton startProgramButton("Start Program");
connect(&startProgramButton, SIGNAL(clicked()), &wrapper, SLOT(startProgram()));
// Show the button.
startProgramButton.setVisible(true);
// Start Qt's event loop.
app.exec();
}
This should give you a 'Start Program' button which, when pressed, will call ConsoleApp::run() method.
While this example is not Qt Designer based I hope this example helps you hunderstand how signals and slots work in Qt.
Cheers,
Jonny
If you have a button created with the Designer you can use on_myButton_clicked() slot in the parent widget class, just like in WinForms.
I'm just trying to get into QT (and KDE) program, and have hit a snag trying to add a floatable, draggable QDockWidget to the .ui file (based as a QWidget) that is embedded into my KDE 4 program.
This is all from the basic template provided by KDevelop 4, so while I understand what's going on, I just don't know the best way to change it.
Here's the deal: main.cpp spawns a new AEmpire window, which starts the whole show off:
AEmpire::AEmpire()
: KXmlGuiWindow(),
m_view(new AEmpireView(this)),
m_printer(0)
{
// tell the KXmlGuiWindow that this is indeed the main widget
setCentralWidget(m_view);
setupActions();
setupGUI();
}
When a new AEmpireView(this) is created (which inherits from QWidget) and is assigned to m_view, this constructor is called:
AEmpireView::AEmpireView(QWidget *)
{
ui_aempireview_base.setupUi(this);
settingsChanged();
setAutoFillBackground(true);
}
So, when I am editing the ui to my program in QT Designer, I'm actually editing the AEmpireView_base ui file, which is a QWidget. It just represents the main view of the KXmlGuiWindow (derived from QMainWindow) and is loaded at runtime.
So, how do I add floatable, draggable QDockWidgets into my main application? Is designing them separately, and add them to the UI the best option? Or maybe removing the entire AEmpireView class, and making my ui file directly represent a KXmlGuiWindow object to be loaded by the AEmpireClass?
Or am I totally overlooking something obvious? Thanks for reading!
I would design the QDockWidget contents as separate UI files. Then create them and stick them into the QDockWidgets in the AEmpire constructor.