Qt and C++ - my own class and signals/slots - c++

I've started learning Qt with C++ by writing a simple GUI. At the beginning, after I had learnt mechanism of signals and slots I decided to write program which gives us ability to control industrial robot arm. So the idea is simple: We've 6 buttons and depending on which one we pressed, then a text appears describing what have we done; for example: "Arm moved to the left".
I am going to build it up but first I have some questions to you.
Here is my code:
Arm.h:
#ifndef ARM_H
#define ARM_H
#include <QVector>
#include <QString>
#include <QLabel>
class Arm{
public:
Arm();
static void displayMoves(QLabel *ptrQLabel); //function for display QString listMoves
QVector<bool(*)(void)> vctrMovesFun; //contains pointers for function which defines moves of industrial robot
private:
static QString listMoves; //contain every move which industrial robot has done
static bool moveArmForward();
static bool moveArmBackward();
static bool moveArmLeft();
static bool moveArmRight();
static bool spinArmLeft();
static bool spinArmRight(); //all this functions define moves of robot's arm
};
#endif // ARM_H
Arm.cpp:
#include "arm.h"
QString Arm::listMoves = ""; //empty string
//***************************************************************
Arm::Arm(){
vctrMovesFun = {&moveArmForward, &moveArmBackward, &moveArmLeft,
&moveArmRight, &spinArmLeft, &spinArmRight}; //set reference to functions
}
//***************************************************************
bool Arm::moveArmForward(){
listMoves+= "Arm moved forward\n";
return true;}
//***************************************************************
bool Arm::moveArmBackward(){
listMoves+= "Arm moved backward\n";
return true;}
//***************************************************************
bool Arm::moveArmLeft(){
listMoves+= "Arm moved to the left\n";
return true;}
//***************************************************************
bool Arm::moveArmRight(){
listMoves+= "Arm moved to the right\n";
return true;}
//***************************************************************
bool Arm::spinArmLeft(){
listMoves+= "Arm spinned to the left\n";
return true;}
//***************************************************************
bool Arm::spinArmRight(){
listMoves+= "Arm spinned to the right\n";
return true;}
//***************************************************************
void Arm::displayMoves(QLabel *ptrQLabel){
ptrQLabel -> setText(listMoves);
}
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "arm.h"
#include <QMainWindow>
#include <QPushButton>
namespace Ui {
class MainWindow;}
class MainWindow : public QMainWindow{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QPushButton *button0;
QPushButton *button1;
QPushButton *button2;
QPushButton *button3;
QPushButton *button4;
QPushButton *button5;
QLabel *label;
Arm arm;
private slots:
void useVector0();
void useVector1();
void useVector2();
void useVector3();
void useVector4();
void useVector5();
};
#endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui -> setupUi(this);
this -> setGeometry(0,0,800,700);
this -> setStyleSheet("background-color:rgb(188, 198 ,204)");
button0 = new QPushButton("Move forward", this);
button0 -> setGeometry(50,50, 100,50);
button0 -> setStyleSheet("background-color:rgb(108, 118, 143)");
connect(button0, SIGNAL (clicked()), this, SLOT (useVector0()));
button1 = new QPushButton("Move backward", this);
button1 -> setGeometry(50,150, 100,50);
button1 -> setStyleSheet("background-color:rgb(108, 118, 143)");
connect(button1, SIGNAL (clicked()), this, SLOT (useVector1()));
button2 = new QPushButton("Move left", this);
button2 -> setGeometry(50,250, 100,50);
button2 -> setStyleSheet("background-color:rgb(108, 118, 143)");
connect(button2, SIGNAL (clicked()), this, SLOT (useVector2()));
button3 = new QPushButton("Move right", this);
button3 -> setGeometry(50,350, 100,50);
button3 -> setStyleSheet("background-color:rgb(108, 118, 143)");
connect(button3, SIGNAL (clicked()), this, SLOT (useVector3()));
button4 = new QPushButton("Spin left", this);
button4 -> setGeometry(50,450, 100,50);
button4 -> setStyleSheet("background-color:rgb(108, 118, 143)");
connect(button4, SIGNAL (clicked()), this, SLOT (useVector4()));
button5 = new QPushButton("Spin right", this);
button5 -> setGeometry(50,550, 100,50);
button5 -> setStyleSheet("background-color:rgb(108, 118, 143)");
connect(button5, SIGNAL (clicked()), this, SLOT (useVector5()));
label = new QLabel("", this);
label ->setStyleSheet("background-color:rgb(0, 0, 0)");
label -> setGeometry(300,50,300,600);
}
//************************************************************************
MainWindow::~MainWindow(){
delete ui;
}
//*************************************************************************
void MainWindow::useVector0(){
arm.vctrMovesFun[0]();
arm.displayMoves(label);}
//*************************************************************************
void MainWindow::useVector1(){
arm.vctrMovesFun[1]();
arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector2(){
arm.vctrMovesFun[2]();
arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector3(){
arm.vctrMovesFun[3]();
arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector4(){
arm.vctrMovesFun[4]();
arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector5(){
arm.vctrMovesFun[5]();
arm.displayMoves(label);
}
main.cpp:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
As you can see there is nothing special. My questions:
I don't understand ui in MainWindow class. What is it and how can it be helpful in Qt?
When I create vector of pointers to my functions I need to make them static, in another way I can't put them into vector. Why? (class Arm)
Constructor in MainWindow. Generally constructor is being called only once when we are creating our object, so why method connect in MainWindow.cpp work for the whole program?
As you can see, there is 6 method to use my own function. I named them for example as: void useVector0(). I am truly sure that it's very bad to do. There should be one method but if I do something like:
void MainWindow::useVector(unsigned short k){
arm.vctrMovesFun[k]();
arm.displayMoves(label);
I can't use it as a slot because signal clicked() has no arguments. How to solve it? Overload clicked() method?
Maybe you have a general opinion about my code so write it. I'll be very happy for every words of criticism.

As others have already pointed out, your question needs some improvement. I suggest you read How to ask, where you'll find nice guidlines about what can I ask around here and how do I ask a nice question.
Nonetheless, I'm going to give you a brief answer to your questions, hoping that it will allow you to ask a more specific, new question, if you have one.
What are .ui files, of a "Qt-Form-Class" good for?
Right now you are creating your buttons inside of the MainWindow's constructor. That might be okay for simple GUIs, but you have to kind of "guess" the positions of the buttons.
If you use the Qt Designer you can create your layouts with the help of some tools. Once you've placed some elements with the designer you will be able to access them from code like this:
ui->label1->setText("hello World");
You can connect those UI widgets' signal to slots either by using connect() in your code or by using the Designer to add them to the UI file.
How can I create a pointer to a member function?
http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions
Not sure what you're asking here
How can I execute different code in a slot, depending on the sender?
Take a look at QSignalMapper.
It will not give you a unsigned short k as you asked for, but a QString depending on which widget emitted the signal.
Could you review my code?
Now that's definitely a question for the Code Review Stack Exchange site.

QMainWindow is basically same as QWidget when used as a (guess what) main window, the noticeable difference is that QWidget expects you to have only 1 window in ur application, while QMainWindow is more about serving as the most important window which will "control" all the rest (like alert message boxes for example). you really should use QWidget as the base in most cases unless you are sure you even need QMainWindow.
i am not completely sure about it so please don't count it as a biblical rule, but if i remember correctly: member class functions are not duplicated per object, means every instance of the class calls the one and only address assigned to the function in class creation. in other words - they are static.
notice, that "everywhere" in the program is actually inside the constructor itself. kek.
most of Qt coding happens in the scope of the main window constructor function upon it's creation. it is a bit hard to understand if you are used to main() inside main.cpp . ofcourse the "connect" method is working anywhere inside the constructor because the constructor is in the same scope as any other method of the class (constructor is a method too afterall)
indeed there is a better way. the new "connect" version of qt5 is taking a reference to both signal and slot functions instead of macros SLOT() and SIGNAL(), means you can fit-in more dynamically and flexibly. you shall adopt that new version or at least know about it's existence, as it is awesome. (you are using qt4 version of connect, which is still supported tho)
unfortunately, TLDR :D
you can take it as a critics. good luck in your project m9

I don't understand ui in MainWindow class. What is it and how can it be helpful in Qt?
Currently you're creating your GUI in code. However, there are applications (like Qt Creator's "Design" mode) that will write the code that creates your GUI for you. The problem with that is that, if you then edit that code, Qt Creator will have a very hard time reconciling your modifications with any changes it wants to make.
To avoid the issue, you use the object in the ui instance variable. That object is what Qt Creator generates, and you don't touch that code. Instead, all your code goes into your MainWindow.
When I create vector of pointers to my functions I need to make them static, in another way I can't put them into vector. Why? (class Arm)
static functions are standalone functions. They don't have an object associated with them. Member functions (non-static functions in an object) on the other hand, have a "this". So, to call a standalone function, you just call MyFunction( 1 ) or whatever, whereas to call a member function, you need to tell it which object's member function you want to call (myObject->MyMemberFunction( 1 )).
Your is defined to hold pointers to standalone functions, so doesn't have any room to store the object pointers to go with a member function.
If you want to learn more about pointers to member functions, look up that topic in any good C++ textbook. That said, Qt hides C++'s pointers to member functions behind slots and signals. So you might just want to not keep an array and instead define an array of those.
Constructor in MainWindow. Generally constructor is being called only once when we are creating our object, so why method connect in MainWindow.cpp work for the whole program?
There is only one MainWindow object in your project, and it is created at the start of main() and only goes away once main() exits. So it lives just as long as your entire application.
As you can see, there is 6 method to use my own function. I named them for example as: void useVector0(). I am truly sure that it's very bad to do. (...) I can't use it as a slot because signal clicked() has no arguments.
I think you want QSignalMapper for that: Passing an argument to a slot

Related

How can I emit a signal of another instance from _clicked() event?

the runnable project is here:
enter link description here
I sincerely glad to have your detail answers to solve this, but I am still confusing on this issue:
case 1: changing socket_session as a member variable of mainwindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
SocketThread* socket_session;
private:
...
But this is not the solution to access setFlag, even after I change the `Form1::on_qpushButton__set_white_level_0_clicked()' function like this:
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
Still it doesn't make sense because form1 instance doesn't have "the" instance of socket_thread which has been instantiated from mainwindow.
There's a solution I think is making another class that includes all instances that I want to use from inside of mainwindow but I don't think that is a good one because I am using thread and accessing a global big instance class that includes all of them to be "shared" is not a good idea for someone like me.
#include <form1.h>
#include <ui_form1.h>
#include "socketthread.h"
Form1::Form1(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form1) {
ui->setupUi(this);
}
Form1::~Form1() {
delete ui;
}
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
enter image description here
I know I am lack of understanding about this but, do I wanna make something nobody does...? I think everyone wants to separate all objects and their methods clearly and communicate via signals or calling functions from delivered object instances...
case 2: ... let me try how you suggested make possible first...
I can read C++ code and overall structure, but I don't know why I have to struggle with this, so please help me, dear Guru.
On socketthread.h :
class SocketThread : public QThread {
Q_OBJECT
public:
QTcpSocket *socket_session;
SocketThread();
~SocketThread(){}
bool connectToServer(QString, int);
void sendData(const char*, int, int);
void run(void);
private:
QString message;
volatile bool threadFlag;
signals:
void changedThreadFlag(void);
void changedMessageStr(void);
void setThreadFlag(bool);
void setMessageStr(QString);
private slots:
void setStr(QString);
void setFlag(bool);
void socketError(QAbstractSocket::SocketError);
};
And its implementation is...
SocketThread::SocketThread() {
socket_session = NULL;
threadFlag = false;
message = "NULL";
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
}
...
void SocketThread::setStr(QString str) {
message = str;
}
void SocketThread::setFlag(bool flag) {
threadFlag = flag;
}
void SocketThread::run() {
while(true) {
if(threadFlag) {
QThread::msleep(100);
qDebug() << message;
} else
break;
}
qDebug() << "loop ended";
}
And I have one form which has a button, and I put a clicked() slot of it like this...
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
--how can I emit the signal of the one of socketthread from here??
}
Now, the mainwindow is like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
QString addr_server = "223.194.32.106";
int port = 11000;
SocketThread* socket_session = new SocketThread();
socket_session->connectToServer(addr_server, port);
ui->setupUi(this);
Form1* form1;
form1 = new Form1();
ui->stackedWidget_mainwindow->addWidget(form1);
ui->stackedWidget_mainwindow->setCurrentWidget(form1);
socket_session->run();
...
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
Once the socket_session->run() started, I need to change the threadFlag by clicking the button by emitting setThreadFlag() of one's from the running thread. And I just stuck in here.
Does it possible even?
Or am I doing this all wrong from the beginning?
As mentioned in this post:
"Emitting a signal" == "calling a function"
So all you really have to do is call the signal function, and all connected slots should be called.
This of course means that the Form1 object needs a pointer to the thread object, i.e. it needs a copy of socket_session. Then you can simply call the signal on the object
socket_session->setThreadFlag(your_flag);
Of course, if the Form1 have a copy of the socket_session pointer, it might as well call setFlag directly, if it was public.
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
No signal is needed – just call the function.
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
// --how can I emit the signal of the one of socketthread from here??
// E.g. this way:
socket_session->setThreadFlag(true);
}
To make this possible, another fix is needed:
socket_session is a local variable in OP's exposed code.
To make it "persistent", it has to become e.g. a member variable.
So, the constructor MainWindow::MainWindow() has to be changed:
// Nope: SocketThread* socket_session = new SocketThread();
// Instead:
socket_session = new SocketThread();
and SocketThread* socket_session; has to be added to member variables of class MainWindow.
To make it accessible in Form1, it has to be passed to Form1 as well.
This could be done e.g. by making it a member variable in Form1 also which is initialized with a constructor argument (or set from MainWindow afterwards).
(I must admit that I never have used the Qt UI builder QtDesigner but build all my UIs by C++ code exclusively.)
But, now, another fix is necessary:
volatile doesn't make a variable suitable for interthread communication.
(This was used in ancient times before multi-threading started to be supported by C++11.)
However, this is wrong: Is volatile useful with threads?
An appropriate fix would be to use std::atomic instead:
// Wrong for interthread-com.
//volatile bool threadFlag;
// Correct:
std::atomic<bool> threadFlag; // #include <atomic> needed
FYI: SO: Multithreading program stuck in optimized mode but runs normally in -O0
And, finally, in SocketThread::SocketThread():
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
is not necessary in this case.
SocketThread::setThreadFlag() could call SocketThread::setFlag() directly, or even write threadFlag itself:
void setThreadFlag(bool flag) { threadFlag = flag; }
As I (recommended to) make threadFlag atomic, it can be accessed from any thread without causing a data race.
Update:
After OP has updated the question:
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
The button (created from UI Form1) can be connected in the MainWindow as well (without using any method of Form1):
QObject::connect(form1->button1, &QPushButton::clicked,
socket_session, &SocketThread::setThreadFlag,
Qt::QueuedConnection);
Notes:
About form1->button1, I'm not quite sure.
I noticed that widgets in UI generated forms can be accessed this way but I don't know the exact details (as I never used the Qt UI builder on my own).
I used the Qt5 style of QObject::connect().
This is what I would recommend in any case.
The Qt5 style is verified at compile time. –
Wrong connections are detected by the C++ type checking.
Additionally, any function with matching signature can be used – no explicit exposure of slots is anymore necessary.
Even conversion of non-matching signature or adding additional parameters becomes possible by using C++ lambdas which are supported as well.
Qt: Differences between String-Based and Functor-Based Connections
It is possible to connect signals and slots of distinct threads.
I used Qt::QueuedConnection to remark this as interthread communication.
(However, I roughly remember that Qt might be able to detect it itself.
See the doc. for Qt::AutoConnection which is the default.
Further reading: Qt: Signals & Slots
Btw. using the Qt signals for inter-thread communication would exclude the necissity to make SocketThread::threadFlag() atomic. It could become a simple plain bool threadFlag; instead. The slot SocketThread::setThreadFlag() is called in the Qt event loop of QThread, in this case.

Qt adding child widget in resizeEvent

I have a widget W deriving from QFrame with layout set to an instance of QVBoxLayout. I wonder if the following resizeEvent implementation is correct or is it going to cause an infinite loop:
void W::resizeEvent(QResizeEvent *event) {
for (/* some condition based on the new size of this widget */) {
// Infinite loop or not?
qobject_cast<QVBoxLayout *>(layout())->addWidget(new QWidget());
}
}
So far it worked for me, is this by pure luck?
This is okay. W owns a QLayout which owns QWidget. Adding the QWidget to the QLayout does not change the size of W. You see this all the time. For example, if you place a child widget in a parent and the parent is too small, the child widget will be clipped. Stately differently, the size of the parent does not stretch to accommodate the size of the child. I believe your code would be a typical way to hide or show widgets based on the size of the parent (for example, when the window size changes).
Painting and constructing a hierarchy of widgets are two different things. So, adding QWidgets is just fine, but using QPainter directly in resizeEvent not.
Hierarchy of QWidgets
A hierarchy of QWidgets derivatives (QLineEdit, QPushButton, ...) is a high level specification of how the graphical user interface should look like and may be ordered using QLayout items.
Painting
Painting (using QPainter) is the process of actually drawing something on the screen and is purely done in the virtual function QWidget::paintEvent. Every derivative of QWidget should provide an implementation of this empty base function. The default derivatives (QLineEdit, ...) provide an implementation of paintEvent based on their current state (size of the widget, current text for a QLineEdit, ...) and the current QStyle object, which is typically automatically set based on your OS, but may be changed programmatically using QWidget::setStyle or QApplication::setStyle. A repaint can be requested using QWidget::update.
"Should not/need not" vs "may not"
The sentence "No drawing need be (or should be) done inside this handler." is meant for people implementing a custom QWidget (with a new implementation of paintEvent) to make it clear that you should not implement your painting here, but that a paintEvent will be automatically triggered.
"Should not/need not" is some advice, they do not write "may not". So, if you for some reason (ex. real-time applications) want an immediate screen refreshment, you may invoke a repaint immediately using repaint, resulting in paintEvent being called during resizeEvent. As long as all the QPainter operations on a QWidget are inside a paintEvent (as required by the warning in the QPainter documentation), everything is just fine.
Adding widgets to the layout, using addWidget, within the resizeEvent function is not a problem as it does not instantly trigger a drawing.
You can easily verify this by compiling and executing this simple project:
dialog.h:
#pragma once
#include <QDialog>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
void resizeEvent(QResizeEvent *event);
void paintEvent(QPaintEvent *event);
private:
bool resizing;
};
dialog.cpp:
#include "dialog.h"
#include <QResizeEvent>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>
Dialog::Dialog(QWidget *parent)
: QDialog(parent),
resizing(false)
{
new QVBoxLayout(this);
}
Dialog::~Dialog()
{
}
void Dialog::resizeEvent(QResizeEvent *event)
{
resizing = true;
if ( event->size().width() == event->size().height() )
{
qDebug() << "Adding widget";
// Infinite loop or not?
layout()->addWidget(new QPushButton());
}
resizing = false;
}
void Dialog::paintEvent(QPaintEvent *event)
{
if ( resizing )
{
qDebug() << "Painting while resizing widget";
}
}
main.cpp:
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
When you run the program, resize the dialog to make it be square (width==height), some buttons are inserted ("Adding widget" is printed to the console), but you'll never see "Painting while resizing widget" message. This is most likely because addWidget sets a dirty display flag that is processed later by the framework. It invalidates the display, but does not repaint it right away.
So what you are doing is fine and does not violate the framework requirement ("No drawing need be (or should be) done inside this handler.").
However, if you are not confident (maybe the painting could be operated right away on different OS, or in future Qt versions....you can't be sure), you can also delay the insertion by emitting a signal connected to a slot using Qt::QueuedConnection, this slot would be executed "later" and then do the call to addWidget, guaranteeing that it's done outside the resizeEvent function.

QT/c++ call class function with pushbutton

i have an UI with two buttons. My first button read an xml file. The second button should create an window an show a circle.
I have a mainwindow.h and a circle.h. Now i want to start my circle function with a pushbutton click.
My circle function:
void circle::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(QBrush("#888"), 1));
painter.setBrush(QBrush(QColor("#888")));
qDebug() << "\r\nxarray : " <<"test";
for(int z = 0; z < 50; z++)
{
painter.drawEllipse(10, 10, 100, 100);
}
}
Atm i start it with:
circle::circle(QWidget *parent)
: QWidget(parent)
{}
But i want to start it with:
void MainWindow::on_pushButton_clicked(
{}
How can i start my function with the pushButton?
[I just started to learn qt/c++ so im a beginner]
greetings
In the slot on_pushButton_clicked() create an instance of the class circle and call the required method through that instance.
EDIT:
I do not know what method you intend to call in the circle class. But assuming you have a function called myFunc(), the code would be something like:
void MainWindow::on_pushButton_clicked()
{
circle* circleObj = new circle(this); // instance created
circleObj->myFunct(); // the necessary actions are done in this function
// connect the signals from the circle class if any to the required slots in MainWindow
connect(circle, SIGNAL(mySignal()), this, SLOT(mySlot());
}
Since you seem to be completely new to Qt looking at your comments, I highly recommend you go through the documentation and the awesome tutorials at the VoidRealms YouTube channel before proceeding further.
Qt uses signal and slot system for specifying actions triggered by the user. So if you specify function on_pushButton_clicked you should do the following:
Write Q_OBJECT macro in the beginning of your MainWindow definition (class containing a slot)
Write on_pushButton_clicked in private slots: section of your class (instead of normal private: section)
Write call to QObject::connect somewhere (possibly in constructor) with the following syntax: connect (button, SIGNAL(clicked ()), this, SLOT(on_pushButton_clicked ()));, read Qt manual for which signals are available.
Rerun qmake if you're using Visual Studio.
Specifically to do what you want in your case, you probably need to create some flag which will be set in on_pushButton_clicked function and check for this flag in paintEvent.
Additional info about signal and slots from Qt documentation: http://doc.qt.io/qt-5/signalsandslots.html

Must construct a QApplication before a QWidget

Everywhere only just "before QPaintDevice" questions and nowhere is my error. So, here we go.
I need an extern QWidget to be able to get access to it from outside (because I don't know any other ways to do it). Basically, I need this: Create 2 QWidgets from 1 window, go to first window and from there hide main window and show second window created by main window (although main window is not main(), it is QWidget too).
I added
extern QWidget *widget = new QWidget
everywhere and everyhow in possible ways, and I still got this message. I suppose, it means that I need to create my QApplication (in main.cpp) and only then declare any QWidgets. But then HOW can I access those QWidgets from another QWidgets?
Code is here:
https://github.com/ewancoder/game/tree/QWidget_before_QApp_problem
P.S. The final goal is to be able show and hide both gamewindow.cpp and world.cpp from battle.cpp (just regular class)
And btw, adding Q_OBJECT and #include both don't work.
Anyway, if I cannot use functions from one window to another, than what's the point? I can have one window in another, and then another in that one, and then one in that another... but I can't do anything from the last to the previous. After years on Delphi that seems strange to me.
Don't use extern or otherwise static variables which lead to creation of the widget before the QApplication is created in main. The QApplication must exist before the constructor of the QWidget is executed.
Instead of sharing the variable via extern, either make the other windows members of the main window, and then make the windows known to each other by passing around pointers, or keep them private in MainWindow and request the actions from the subwindows e.g. via signal/slots. As a generic rule, don't use global variables but class members.
In the following FirstWindow (which is supposed hide main window and secondWindow) gets the main window and the second window passed via pointers and then just calls show/hide on them directly.
int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
In main window, have two members for the two other windows, say FirstWindow and SecondWindow:
class MainWindow : public QMainWindow {
...
private:
FirstWindow *m_firstWindow;
SecondWindow *m_secondWindow;
};
MainWindow::MainWindow(QWidget *parent) {
m_firstWindow = new FirstWindow; //not pass this as parent as you want to hide the main window while the others are visible)
m_secondWindow = new SecondWindow;
m_firstWindow->setMainWindow(this);
m_firstWindow->setSecond(m_secondWindow);
m_firstWindow->show(); //Show first window immediately, leave second window hidden
}
MainWindow::~MainWindow() {
//Manual deletion is necessary as no parent is passed. Alternatively, use QScopedPointer
delete m_firstWindow;
delete m_secondWindow;
}
FirstWindow, inline for brevity:
class FirstWindow : public QWidget {
Q_OBJECT
public:
explicit FirstWindow(QWidget *parent = 0) : QWidget(parent) {}
void setMainWindow(MainWindow *mainWindow) { m_mainWindow = mainWindow); }
void setSecondWindow(SecondWindow *secondWindow) { m_secondWindow = secondWindow; }
private Q_SLOTS:
void somethingHappened() { //e.g. some button was clicked
m_mainWindow->hide();
m_secondWindow->show();
}
private:
MainWindow* m_mainWindow;
SecondWindow* m_secondWindow;
};
Maybe not helping the former author, but others facing the problem.
I simply got this error by mistaking a debug-library with a release one. So check your linker settings, if you are sure the implementation is done right (first instancing application and then using widgets).

Qt No matching function for call to mainWindow::connect()

I'm trying to connect a combo box value and a label such that when the combo box changes the label reflects that. I have googled my heart out trying to find an answer but, as of yet, nothing has worked; I still get the error:no matching function for call to mainWindow::connect(QComboBox*&, const char [38], QString*, const char [26])
I have tried QObject::connect, QWidget::connect and anything else dealing with Qt, but to no avail.
Creating a label that says the combo box value is not my final intention for the program. Rather, I wish to get it working with a simple label then change it to what I want it to display (thus the tempLabel).
mainwindow.h:
class MainWindow : public QMainWindow
{
public:
MainWindow();
private slots:
QString getClass(QComboBox *box);
};
mainwindow.cpp:
MainWindow::MainWindow()
{
QString qMathClassName;
QComboBox* mathClassCombo = new QComboBox;
QLabel* label = new QLabel(qMathClassName);
// omitting layout code...
connect(mathClassCombo, SIGNAL(currentIndexChanged(const QString &)),
&qMathClassName, SLOT(getClass(mathClassCombo)));
}
QString MainWindow::getClass(QComboBox *box)
{
return box->currentText();
}
Any help would be greatly appreciated!
You are connecting a signal to a slot with a different signature. You have to change your slot to something like
getClass(const QString &)
to match currentIndexChanged signal.
I think you need to read Qt's signals and slots documentation. Again, if you've already done so. Pay special attention to their examples.
I think that you had these misconceptions about Qt in C++:
That QLabel takes a reference to a QString, and that it will update its text when that string changes. It won't. QLabel will display the value of the string when you give it the string. That is the only time it will update.
That objects constructed on the stack will not be destroyed at the end of the function. They will not. At the end of the constructor, qMathClassName will be destroyed and any reference to it will become invalid. Thus, you'd not want to make a connection to it, even if you could.
That the third argument of QObject::connect is a pointer to a place to put the return value for the slot. It's not. The third argument is a pointer to the QObject on which to call the slot. The return value of a slot is unused for any calls made to it via QObject::connect.
That you can bind values to slots in your connection. Unfortunately not. Within the SLOT macro, you must put the function signature of the slot. You may not reference any variables. The arguments section must have only class names. That is SLOT(getClass(QComboBox*)), not SLOT(getClass(mathClassCombo)).
The simplest way to ensure the contents of a combo box are displayed in a label are this:
QComboBox* mathClassCombo = new QComboBox;
QLabel* tempLabel = new QLabel;
connect(mathClassCombo, SIGNAL(currentIndexChanged(const QString&)),
tempLabel, SLOT(setText(const QString&)));
If you want to do something more complicated, I recommend just making a slot on your window that can handle those complications. For example:
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
private slots:
void updateLabelText(const QString& className);
private:
QComboBox* mathClassCombo;
QLabel* tempLabel;
}
mainwindow.cpp:
MainWindow::MainWindow()
{
mathClassCombo = new QComboBox;
tempLabel = new QLabel;
// omitting layout code...
connect(mathClassCombo, SIGNAL(currentIndexChanged(const QString&)),
this, SLOT(updateLabelText(const QString&)));
}
void MainWindow::updateLabelText(const QString& className)
{
QString newLabelString = className + " is the best class ever!";
tempLabel->setCurrentText(newLabelString);
}