Qt C++ QLabel Clickable mouse events doesn't work - c++

I have a big doubt and problem. After try a lot of tutorials and examples, I cannot receive signal clicks in my QLabel. If I do the same, but in a QDialog (not in a QLabel), I can know the status of the mouse.
I paste my example code, before that, I present my steps to make the project:
I make a project, make a QMainWindow (named testWindow, maked graphically), after that, I add a QLabel (lblMouse), I mark the mouseTracking property as true. After execute, my QLabel lblMouse doesn't react to my mouse events.
Another doubt is: after execute my program, the text of my QLabel is not "Hello" as I assign in his constructor, it will be executed after ui is executed? I can change it from the constructor of the ui with ui->lblMouse->setText("Hello"); (Probably I have an error, I'm a C programmer and I'm trying to enter in the C++ world)
After that, I edit the code (testWindow.cpp and testWindow.h):
Here is my cpp code:
testWindow::testWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::testWindow)
{
ui->setupUi(this);
//It will not be neccesary because I mark on the checkbox of mouseTracking
ui->lblMouse->setMouseTracking(true);
connect(ui->lblMouse, SIGNAL(Mouse_Pos()), this, SLOT(Mouse_current_pos()));
connect(ui->lblMouse, SIGNAL(Mouse_Pressed()), this, SLOT(Mouse_Pressed()));
connect(ui->lblMouse, SIGNAL(Mouse_Left()), this, SLOT(Mouse_left()));
}
testWindow::~testWindow()
{
delete ui;
}
void testWindow::Mouse_current_pos()
{
ui->lblMouse_Current_Pos->setText(QString("X = aa, Y = aa")/*.arg(ui->lblMouse->x())*/);
}
void testWindow::Mouse_Pressed()
{
ui->lblMouse_Current_Pos->setText(QString("X = aa, Y = aa")/*.arg(ui->lblMouse->x())*/);
}
void testWindow::Mouse_left()
{
ui->lblMouse_Current_Pos->setText(QString("X = aa, Y = aa")/*.arg(ui->lblMouse->x())*/);
}
lblMouse::lblMouse(QWidget *parent): QLabel(parent)
{
// strange for me, the initial text of the label is not Hello
this->setText("Hello");
}
lblMouse::~lblMouse()
{
}
void lblMouse::mouseMoveEvent(QMouseEvent *ev)
{
this->xpos = ev->x();
this->ypos = ev->y();
emit Mouse_Pos();
}
void lblMouse::mousePressEvent(QMouseEvent *)
{
emit Mouse_Pressed();
// ev->x();
}
void lblMouse::leaveEvent(QEvent *)
{
emit Mouse_Left();
}
Here is my h file:
#ifndef TESTWINDOW_H
#define TESTWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QMouseEvent>
#include <QEvent>
#include <QDebug>
namespace Ui {
class testWindow;
class lblMouse;
}
class lblMouse : public QLabel
{
Q_OBJECT
public:
explicit lblMouse(QWidget *parent = 0);
~lblMouse();
int xpos,ypos;
void leaveEvent(QEvent *);
protected:
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
signals:
void Mouse_Pressed();
void Mouse_Pos();
void Mouse_Left();
};
class testWindow : public QMainWindow
{
Q_OBJECT
public:
explicit testWindow(QWidget *parent = 0);
~testWindow();
private:
Ui::testWindow *ui;
private slots:
void Mouse_current_pos();
void Mouse_Pressed();
void Mouse_left();
};
#endif // TESTWINDOW_H
Also, here is my .ui file (thanks #Thomas ):
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>testWindow</class>
<widget class="QMainWindow" name="testWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="lblMouse">
<property name="geometry">
<rect>
<x>20</x>
<y>60</y>
<width>331</width>
<height>241</height>
</rect>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="text">
<string>Mouse Area</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>400</x>
<y>50</y>
<width>201</width>
<height>191</height>
</rect>
</property>
<property name="title">
<string>Mouse Events</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblMouse_Current_Pos">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="text">
<string>x=0, Y=0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblMouse_Current_Event">
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuMenu">
<property name="title">
<string>&Menu</string>
</property>
<addaction name="actionImportar"/>
</widget>
<addaction name="menuMenu"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionImportar">
<property name="text">
<string>&Importar...</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
Edit:
I'm seing a runtime error in the console (is not a compilation error, I got this messages after run the program, but it continues running):
QObject::connect: No such signal QLabel::Mouse_Left() in
../testwindow.cpp:17
QObject::connect: (sender name: 'lblMouse')
QObject::connect: (receiver name: 'testWindow')
PD: I'm not sure if it is the problem. I have tested other ways to do this and I have not good results.
Thanks!

Your label in ui is QLabel class, but you have created lblMouse. So, in ui you must change code
<widget class="QLabel" name="lblMouse">
to
<widget class="lblMouse" name="lblMouse">
EDIT:
To change this you can:
Use any text editor;
Go to Designer in Qt Creator chosing your ui, select your QLabel, call context menu and click "Promote to...". Then check that "Base class name" is correct (QLabel), write your class (lblMouse) in "Promoted class name" field, click "Add" button, then "Promote" button. That's all. Your label now your own label class.
About setText() method.
Go to designer;
Choose your label;
In right side in object propeties find QLabel area and click on a round arrow front of "text" property. That's all. Now, if you do setText() method in constructor - it will works.

You just need to use your lblMouse class.
In .h file, add this in class testWindow
lblMouse *lblMouse_Current_Pos;
In .cpp file, add this in contructor:
lblMouse_Current_Pos = new lblMouse(this);
lblMouse_Current_Pos->setMouseTracking(true);
connect(lblMouse_Current_Pos, SIGNAL(Mouse_Pos()), this, SLOT(Mouse_current_pos()));
connect(lblMouse_Current_Pos, SIGNAL(Mouse_Pressed()), this, SLOT(Mouse_Pressed()));
connect(lblMouse_Current_Pos, SIGNAL(Mouse_Left()), this, SLOT(Mouse_left()));

Related

How to add a "new tab" on an existing QTabWidget using a QPushButton

I am trying to add a "new tab" on an existing QTabWidget using a QPushButton as shown below:
The problem I have is that as I push the button nothing happens and no "new tab" is added.
I set all the proper connection and slots but something is preventing me from adding it to the QTabWidget. Basically nothing happens as I push the button.
Below the minimal verifiable example:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void newTab();
private slots:
void on_addTabBtn_clicked();
private:
Ui::MainWindow *ui;
};
mainwindow.cpp
#include <QLabel>
#include <QTabBar>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tabWidget->clear();
ui->tabWidget->addTab(new QLabel("+"), QString("+"));
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &MainWindow::on_addTabBtn_clicked);
newTab();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::newTab()
{
int position = ui->tabWidget->count() - 1;
ui->tabWidget->insertTab(position, new QLabel("Insert New Tab"), QString("New Tab"));
ui->tabWidget->setCurrentIndex(position);
auto tabBar = ui->tabWidget->tabBar();
tabBar->scroll(tabBar->width(), 0);
}
void MainWindow::on_addTabBtn_clicked()
{
int index = 0;
if(index == this->ui->tabWidget->count() - 1) {
newTab();
}
}
In case you would also like to see the simple .ui file see below:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>279</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
</widget>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addTabBtn">
<property name="text">
<string>Add Tab</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
I tried to solve the problem in many ways and researched what the cause might be. I came across several references such as this one, this and also this one but none of them helped to completely solve the problem.
I am sure that the property of currentChanged is correct, however the callback to trigger the button is not doing the job despite there are no errors in the terminal.
What am I missing? Thanks for pointing to the right direction for solving this issue.
connect the clicked signal of the button to the addTab function/slot of the tabwidget (or to an intermediate function/lambda that calls addTab on the correct destination object).
For example:
connect(ui->addTabBtn, &QPushButton::clicked, this, [&] { ui->tabWidget->addTab(new QLabel("+"), QString("+")); });
Or something along those lines.

Make a Character Counter for a QLineEdit

I am trying to make a simple character counter, like the one in twitter, in QT specifically with the QLineEdit feature. Ideally, it should record the number of characters entered in a QLineEdit and display the number recorded in a separate display label. For example, spotify has a character counter when naming and adding a description to a playlist.
The function that I have declared to count the number of characters entered in the QLineEdit is defined like so:
void MainWindow::countChar()
{
QString tempString = ui->displayLabel->text(); //temp variable to hold the lineEdit's text
int output = tempString.size(); //to get the number of characters in the lineEdit
QString s = QString::number(output);//convert an int to QString
ui->CharCounter->setText(s); //display the number in the displayLabel(CharCounter)
ui->CharCounter->adjustSize();
}
I call this function in my main.cpp under the object, w.
w.countChar();
The reason I want to create a character counter function is because I have set a character limit for the QLineEdit so whatever the user enters can be filled into the main displayLabel at the minimum size of the window. I have done that by writing another function:
void MainWindow::setlineInputTextCharLimit(int limit)
{
ui->inputText->setMaxLength(limit);
}
Which I called under the same object, w:
w.setLineInputTextCharLimit(200);
QTCreator is able to successfully build but the charCounter displayLabel does not change in value after I enter some amount of text into the QLineEdit.
image of the application built
It is clear that the displayLabel for the character counter is being read and has been activated however when I enter any amount of text, the value does not change.
The result after there is some text entered into the QLineEdit
So if the displayLabel is registered and a value is being shown, the function should be working but there is definitely something wrong with it too because the value not change to anything from that '0'?.
Edit: the UI file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>463</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>80</x>
<y>20</y>
<width>311</width>
<height>211</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="inputText"/>
</item>
<item>
<widget class="QPushButton" name="textBtn">
<property name="text">
<string>Display Text</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="displayLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="CharCounter">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
And heres the signal-slot connection:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->textBtn, &QPushButton::clicked, this, &MainWindow::setText);
connect(ui->inputText, &QLineEdit::textChanged, this, &MainWindow::countChar);
}
If you want to count the texts you must count each time the text changes and for that you must use the textChanged() signal, in the following code I show an example:
#include <QApplication>
#include <QLabel>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QWidget>
class CounterWidget: public QWidget
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(int maxLenght READ maxLenght WRITE setMaxLenght)
Q_PROPERTY(int length READ length)
public:
CounterWidget(QWidget *parent=nullptr):
CounterWidget(200, parent)
{
}
CounterWidget(int maxLength, QWidget *parent=nullptr):
QWidget(parent),
layout(this)
{
layout.addWidget(&lineEdit);
layout.addWidget(&counterLabel, 0, Qt::AlignTop | Qt::AlignRight);
connect(&lineEdit, &QLineEdit::textChanged, this, &CounterWidget::countChar);
connect(&lineEdit, &QLineEdit::textChanged, this, &CounterWidget::textChanged);
lineEdit.setMaxLength(maxLength);
countChar("");
}
QString text() const{
return lineEdit.text();
}
void setText(const QString &text){
lineEdit.setText(text);
}
int maxLenght() const{
return lineEdit.maxLength();
}
void setMaxLenght(int maxLenght){
lineEdit.setMaxLength(maxLenght);
}
int length() const{
return lineEdit.text().size();
}
signals:
void textChanged(const QString & text);
private slots:
void countChar(const QString & text){
QString text_label = QString("%1/%2").arg(text.size()).arg(lineEdit.maxLength());
counterLabel.setText(text_label);
}
private:
QVBoxLayout layout;
QLineEdit lineEdit;
QLabel counterLabel;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CounterWidget w;
w.show();
return a.exec();
}
#include "main.moc"
I was reading the text from QLabel and not QLineEdit. So the part in my code:
QString tempString = ui->displayLabel->text();
was only reading the text from the label when I wanted to read the text entered in the QLineEdit. So I changed the code to:
QString tempString = ui->inputText->text();
and that fixed the problem.
Thanks #FrozenM and #eyllanesc

How to update a window in QT?

Im working on a simple project in QtCreator where you input text into a line_edit which then gets printed after clicking a button. It works but I need to resize the window in order to see the updated/changed display.
So starting off with the main.cpp, I have left it as default after some tests:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
That has the issue I was talking about above. I decided to add w.update(); and see if that fixed the issue, it did not. I thought maybe it was because the program was not looping, so I entered the code in a while(true) loop which also was to no avail.
The mainwindow.cpp file is as follows:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->textBtn, SIGNAL(clicked(bool)), this, SLOT(setText()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setText()
{
QString temp = ui->inputText->text();
ui->displayLabel->setText(temp);
}
MainWindow.hpp:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void setText();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Is there a QObject or predifined function in QT that allows me to update the window or automatically updates the window after a detected user change?
Edit: The UI file might be of importance as well:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>463</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QLabel" name="displayLabel">
<property name="geometry">
<rect>
<x>140</x>
<y>150</y>
<width>251</width>
<height>91</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>130</x>
<y>30</y>
<width>251</width>
<height>81</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="inputText"/>
</item>
<item>
<widget class="QPushButton" name="textBtn">
<property name="text">
<string>Display Text</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
The problem is not the update of the GUI but the QLabel does not change size, the initial size depends on the initial text, and if you set a text with larger size only part of the text will be displayed. To adjust the size of the label to the size of the text you must use adjustSize():
void MainWindow::setText()
{
QString temp = ui->inputText->text();
ui->displayLabel->setText(temp);
ui->displayLabel->adjustSize();
}
On the other hand in Qt5 it is advisable to use the new connection syntax since they have several advantages as indicated by the docs, in your case you must change your code to:
connect(ui->textBtn, &QPushButton::clicked, this, &MainWindow::setText);

QOpenGLWidget does not render in the entire widget

Previously I had difficulties creating a qt application with opengl, I always managed to create a pure opengl application with either SDL or glfw + glew.
But I followed the procedure everyone did in videos, created a class derived from QOpenGLWidget and promoted a widget to this class.
Today I decided to do it differently and it worked, first I created a class derived from QOpenGLWidget and QOpenGLFunctions as described in the qt documentation.
But instead of promoting my widget I used ui-> widget to get its reference in the layout and pass as parameter in the constructor of my class and it worked, at least it worked out well in parts ...
First of all I added a GridLayout to my window and the widget that was referenced inside the layout to better fit the user's screen. However only one piece of the widget is painted, at first I thought the opengl widget was changing the size of my widget, but I added a border through css to see if it was actually that but the widget was in the normal size according to figure:
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>656</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
<string>Open 3D Texture Painter</string>
</property>
<property name="styleSheet">
<string notr="true">#m3dWorkspace{
border: 3px solid red;
}</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QWidget" name="m3dWorkspace" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>656</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="action_Settings"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="action_Settings">
<property name="text">
<string>&Settings</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
mainwindow.cpp
#include <QSettings>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "glworkspace.h"
#include "settings_window.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSettings settings(qApp->applicationDirPath() + "//settings.ini", QSettings::IniFormat);
settings.beginGroup("Render");
if(settings.value("renderApi", "ogl").toString() == "ogl"){
this->m_GLWorkspace = new GLWorkspace(ui->m3dWorkspace);
}else if(settings.value("renderApi", "ogl").toString() == "d3dx"){
///#todo setup render with DirectX
}else if(settings.value("renderApi", "ogl").toString() == "vk"){
///#todo setup render with vulkan
}
settings.endGroup();
this->m_SettingsWin = new SettingsWindow(this);
}
MainWindow::~MainWindow()
{
delete m_SettingsWin;
if(m_GLWorkspace != NULL){
delete m_GLWorkspace;
}
delete ui;
}
void MainWindow::on_action_Settings_triggered()
{
m_SettingsWin->exec();
}
glworkspace.h
#ifndef GLWORKSPACE_H
#define GLWORKSPACE_H
#include <QtOpenGL>
class GLWorkspace : public QOpenGLWidget, protected QOpenGLFunctions{
Q_OBJECT
public:
explicit GLWorkspace(QWidget *parent=0);
~GLWorkspace();
protected:
virtual void initializeGL() Q_DECL_OVERRIDE;
virtual void resizeGL(int w, int h) Q_DECL_OVERRIDE;
virtual void paintGL() Q_DECL_OVERRIDE;
private:
QOpenGLFunctions *m_F;
};
#endif // GLWORKSPACE_H
glwokspace.cpp
#include "glworkspace.h"
GLWorkspace::GLWorkspace(QWidget *parent) :
QOpenGLWidget(parent)
{
QSurfaceFormat format;
format.setVersion(4, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
setFormat(format);
}
GLWorkspace::~GLWorkspace()
{
}
void GLWorkspace::initializeGL()
{
initializeOpenGLFunctions();
this->m_F = QOpenGLContext::currentContext()->functions();
m_F->glClearColor(0.0f, 1.0f, 0.5f, 0.0f);
}
void GLWorkspace::resizeGL(int w, int h)
{
m_F->glViewport(0, 0, w, h);
}
void GLWorkspace::paintGL()
{
m_F->glClear(GL_COLOR_BUFFER_BIT);
}
You forgot to add a layout on m3dWorkspace.
Add one, for example:
this->m_GLWorkspace = new GLWorkspace;
auto layout = new QVBoxLayout;
layout->addWidget(this->m_GLWorkspace);
ui->m3dWorkspace->setLayout(layout);

Qt connect(*sender, *signal, *receiver, *method) doesn't call slots

I'm very new to Qt and also to c++. I tried to do a little Celsius/Fahrenheit converter. On the UI I use QDial and QLCDNumber to respectively change and show the temperature.
Unfortunately only the "standard connect" works:
connect(ui->celsiusDial, SIGNAL(valueChanged(int)), ui->celsiusLcd,SLOT(display(int)));
Spinning the dial leads to change on the LCD-Widget but anything else doesn't work (see the connect(...) calls in dialog.cpp.
The project have a QWidget with the name Dialog that calls the tempconverter.cpp class.
Dialog.cpp:
#include "dialog.h"
#include "ui_dialog.h"
#include "tempconverter.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
TempConverter tempConverterObject(0, this);
TempConverter * tempConverter = &tempConverterObject;
connect(ui->celsiusDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempCelsius(int)));
connect(ui->celsiusDial, SIGNAL(valueChanged(int)), ui->celsiusLcd, SLOT(display(int)));
connect(tempConverter, SIGNAL(tempCelsiusChanged(int)), ui->celsiusDial, SLOT(setValue(int)));
connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempFahrenheit(int)));
connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), ui->fahrenheitLcd, SLOT(display(int)));
connect(tempConverter, SIGNAL(tempFahrenheitChanged(int)), ui->fahrenheitDial, SLOT(setValue(int)));
}
Dialog::~Dialog()
{
delete ui;
}
Here's my TempConverter-class:
Header: tempconverter.h
#ifndef TEMPCONVERTER_H
#define TEMPCONVERTER_H
#include <QObject>
class TempConverter : public QObject
{
Q_OBJECT
public:
TempConverter(int tempCelsius, QObject *parent = 0);
int tempCelsius() const; // const is signature for getters!(that's why they are blue!)
int tempFahrenheit() const;
public slots:
void setTempCelsius(int);
void setTempFahrenheit(int);
signals:
void tempCelsiusChanged(int); // Signals are only declared not "implemented", they are emitted when a event occurs
void tempFahrenheitChanged(int); // Signals are only declared not "implemented", they are emitted when a event occurs
private:
int m_tempCelsius; // internal representation of celsiusTemp <=> Java Attribute
};
#endif // TEMPCONVERTER_H
Class: tempconverter.cpp
#include "tempconverter.h"
#include <QDebug>
TempConverter::TempConverter(int tempCelsius, QObject *parent) : QObject(parent) // this is the constructor
{
qDebug("default constructor");
m_tempCelsius = tempCelsius;
}
void TempConverter::setTempCelsius(int tempCelsius)
{
//qDebug("setTempCelsius");
if(m_tempCelsius == tempCelsius)
return;
m_tempCelsius = tempCelsius;
emit tempCelsiusChanged(m_tempCelsius);
emit tempFahrenheitChanged(tempFahrenheit());
}
void TempConverter::setTempFahrenheit(int tempFahrenheit){
qDebug("setTempFahrenheit");
int tempCelsius = (5.0/9.0)*(tempFahrenheit-32);
setTempCelsius(tempCelsius);
qDebug("setTempFahrenheit");
}
int TempConverter::tempCelsius() const{
return m_tempCelsius;
}
int TempConverter::tempFahrenheit() const{
return (m_tempCelsius*2)+30;
}
And finally my UI looks like this: dialog.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>30</x>
<y>40</y>
<width>331</width>
<height>231</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Celsius</string>
</property>
<widget class="QDial" name="celsiusDial">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>161</width>
<height>141</height>
</rect>
</property>
</widget>
<widget class="QLCDNumber" name="celsiusLcd">
<property name="geometry">
<rect>
<x>3</x>
<y>172</y>
<width>161</width>
<height>41</height>
</rect>
</property>
</widget>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Fahrenheit</string>
</property>
<widget class="QDial" name="fahrenheitDial">
<property name="geometry">
<rect>
<x>0</x>
<y>20</y>
<width>161</width>
<height>141</height>
</rect>
</property>
</widget>
<widget class="QLCDNumber" name="fahrenheitLcd">
<property name="geometry">
<rect>
<x>0</x>
<y>170</y>
<width>161</width>
<height>41</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
Thanks in advance, I really have no clue where the error is coming from.
The problem is that the tempConverterObject variable only exists in the constructor since it has been created in that context, ie it is a local variable and it is removed from memory when that function is executed. The solution is to convert that variable to a member of the class:
*.h
private:
Ui::Dialog *ui;
TempConverter *tempConverter;
*.cpp
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
tempConverter = new TempConverter(0, this);
connect(ui->celsiusDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempCelsius(int)));
connect(ui->celsiusDial, SIGNAL(valueChanged(int)), ui->celsiusLcd, SLOT(display(int)));
connect(tempConverter, SIGNAL(tempCelsiusChanged(int)), ui->celsiusDial, SLOT(setValue(int)));
connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempFahrenheit(int)));
connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), ui->fahrenheitLcd, SLOT(display(int)));
connect(tempConverter, SIGNAL(tempFahrenheitChanged(int)), ui->fahrenheitDial, SLOT(setValue(int)));
}