简体   繁体   中英

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

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:

  1. I don't understand ui in MainWindow class. What is it and how can it be helpful in Qt?

  2. 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 )

  3. 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?

  4. 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?

  5. 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.


  1. 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.


  1. How can I create a pointer to a member function?

    http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions

  1. Not sure what you're asking here

  1. 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.


  1. Could you review my code?

    Now that's definitely a question for the Code Review Stack Exchange site.

  1. 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.

  2. 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.

  3. 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)

  4. 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)

  5. 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM