Currently working on getting threading to work with Qt C++ along with using the clearest method to solve the problem. Below is some code to start 3 threads and count to 10000. What i have at the moment is when u press the start and stop buttons the counters do work (using qDebug). However what I want to do is link the counter variable to 3 labels so that when the counter goes up the label for each thread does too (however had no luck with connect as not sure how to link class methods (specifically ui->label->settext to Thread::get_time())).
Currently I am stuck on the final part, as can't find a way to link to label from inside thread.cpp if anyone can help that would be great. As you can imagine gotten a bit lost and not sure where to go from here.
object.h
#ifndef OBJECT_H
#define OBJECT_H
#include <QObject>
#include <QDebug>
#include <QThread>
#include <QApplication>
#include <QMutex>
class Object : public QObject
{
Q_OBJECT
private:
int timealive;
public:
explicit Object(QObject *parent = 0);
void setup(QThread &thread, QObject &object);
void set_time(int number);
int get_time();
bool Stop;
signals:
public slots:
void worker();
};
#endif // OBJECT_H
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_pushButton_6_clicked();
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
Dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_pushButton_clicked()
{
ui->label->setText(QString::number(12));
}
void Dialog::on_pushButton_2_clicked()
{
}
void Dialog::on_pushButton_3_clicked()
{
}
void Dialog::on_pushButton_4_clicked()
{
}
void Dialog::on_pushButton_5_clicked()
{
}
void Dialog::on_pushButton_6_clicked()
{
}
Main.cpp
#include "dialog.h"
#include "object.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
QThread thread;
Object thread_object;
thread_object.setup(thread,thread_object);
return a.exec();
}
object.cpp
#include "object.h"
Object::Object(QObject *parent) :
QObject(parent)
{
}
void Object::setup(QThread &thread,QObject &object)
{
object.moveToThread(&thread);
thread.start();
connect(&thread,SIGNAL(started()),this,SLOT(worker()));
}
void Object::worker()
{
for(int i = 0; i < 10000; i++)
{
QMutex mutex;
QMutexLocker locker(&mutex);
this->set_time(i);
qDebug() << i;
if(this->Stop)
{
break;
}
}
}
void Object::set_time(int number)
{
timealive = number;
}
int Object::get_time()
{
return timealive;
}
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>286</width>
<height>168</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>40</y>
<width>261</width>
<height>25</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Number</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget_2">
<property name="geometry">
<rect>
<x>10</x>
<y>70</y>
<width>261</width>
<height>25</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Number</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_6">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>261</width>
<height>25</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Number</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
Cheers ION
P.s changed code to reflect that I am now using the correct way for threading.
Related
i am following this tutorial from Qt to create my first porject. I have renamed some Widgets, but I am then consistently using my own names.
But when I now try to acces the text of a label in AddDialog, AddDialog doesn´t seem to have that Label, even tough the names are the same and I have it like in the tutorial.
Here is the code:
carrental.cpp
#include "carrental.h"
#include "stdafx.h"
#include "adddialog.h"
#include "ui_adddialog.h"
CarRental::CarRental(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);
}
void CarRental::on_addButton_clicked()
{
AddDialog dialog(this);
if (dialog.exec()) {
QString carName = dialog.carNameEdit->text();
QString carModel = dialog.carModelEdit->text();
if (!carName.isEmpty() && !carModel.isEmpty()) {
QListWidgetItem* item = new QListWidgetItem(carName, ui.carList);
item->setData(Qt::UserRole, carModel);
ui.carList->setCurrentItem(item);
}
}
}
adddialog.h:
#pragma once
#include <QDialog>
#include "ui_adddialog.h"
class AddDialog : public QDialog
{
Q_OBJECT
public:
AddDialog(QWidget* parent = Q_NULLPTR);
private:
Ui::AddDialog ui;
};
adddialog.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddDialog</class>
<widget class="QDialog" name="AddDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>345</width>
<height>230</height>
</rect>
</property>
<property name="windowTitle">
<string>AddDialog</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>60</x>
<y>50</y>
<width>221</width>
<height>131</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="inputLayout">
<item row="0" column="0">
<widget class="QLabel" name="carNameText">
<property name="text">
<string>Car Name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="nameEdit">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="carModelText">
<property name="text">
<string>Car Model:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="carModelEdit"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="okLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
<connection>
<sender>okButton</sender>
<signal>clicked()</signal>
<receiver>AddDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>251</x>
<y>167</y>
</hint>
<hint type="destinationlabel">
<x>100</x>
<y>196</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Thanks
carNameEdit and carModelEdit are attributes of the private ui object so you cannot access them, a possible solution is to make them public but another better option is to create public methods that expose the strings:
public:
AddDialog(QWidget* parent = Q_NULLPTR);
QString carName() const;
QString carModel() const;
private:
Ui::AddDialog ui;
QString AddDialog::carName() const
{
return ui.carNameEdit->text();
}
QString AddDialog::carModel() const
{
return ui.carModelEdit->text();
}
Then change to:
QString carName = dialog.carName();
QString carModel = dialog.carModel();
Small addition to good answer from #eyllanesc; You can use QObject::findChild Qt feature:
In your case it might be:
QLineEdit *carModelEdit= dialog.findChild<QLineEdit*>("carModelEdit");
qDebug() << carModelEdit->text();
It works, because after ui.setupUi(this); all elements of your UI become children of your widget.
Quite useful for unit testing, but whether you should use it in your production code is a bit questionable.
I'm trying to link pushbuttons using a line that I draw using the paintEvent function, but it's returning wrong values when reading the position of the buttons. this stuff has been tried on simpler projects and it worked but when using several widget container things gets wrong I don't know why.
Image of project result:
Simpler projects:
code's header file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
virtual void paintEvent(QPaintEvent* event);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
code's source file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter paint(this);
QPen pen;
pen.setColor(QColor(56, 163, 220));
pen.setWidth(2);
paint.setPen(pen);
int xstart1 = ui->pushButton_4->pos().x() + ui->pushButton_4->width();
int ystart1 = ui->pushButton_4->pos().y() + (ui->pushButton_4->height() / 2);
int xfinish1 = ui->pushButton_6->pos().x();
int yfinish1 = ui->pushButton_6->pos().y() + (ui->pushButton_6->height() / 2);
paint.drawLine(xstart1, ystart1, xfinish1, yfinish1);
int xstart2 = ui->pushButton_5->pos().x() + ui->pushButton_5->width();
int ystart2 = ui->pushButton_5->pos().y() + (ui->pushButton_5->height() / 2);
int xfinish2 = ui->pushButton_7->pos().x();
int yfinish2 = ui->pushButton_7->pos().y() + (ui->pushButton_7->height() / 2);
paint.drawLine(xstart2, ystart2, xfinish2, yfinish2);
}
code's 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>590</width>
<height>435</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>268</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>183</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QPushButton" name="pushButton_6">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_7">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QTableWidget" name="tableWidget"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="widget_3" native="true">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QPushButton" name="pushButton_8">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>590</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
I'm trying to make a program that has multiple QTreeWidget's. However, my goal is to ONLY allow for 1 QTreeWidget row to be selected at a time.
I've kind of managed to make this happen using the currentItemChanged signal, but it bugs out.
To reproduce the issue...
Select a row on one QTreeWidget.
Select another row on the OTHER QTreeWidget. At this point all QTreeWidget selection are removed (great that's exactly what I wanted).
Select the same row on the same QTreeWidget as step 1. At this point it has now bugged out because your previous selection is still chosen...
Am I clearing the selection improperly, and if so how should I be clearing it?
Here's a picture of the issue.
Here is my source...
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTreeWidget>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void OnSelectedTreeValueChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTreeWidget>
#include <QTreeWidgetItem>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->treeWidget->expandAll();
ui->treeWidget->setItemsExpandable(false);
ui->treeWidget_2->expandAll();
ui->treeWidget_2->setItemsExpandable(false);
connect(ui->treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(OnSelectedTreeValueChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
connect(ui->treeWidget_2, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(OnSelectedTreeValueChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::OnSelectedTreeValueChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
if(current->childCount() == 0)
{
// Get OUR parrent item.
QTreeWidgetItem* parent_item = current->parent();
// Go through each tree & deselect selections.
QObject* sender_object = sender();
QTreeView* sender_tree = static_cast<QTreeView*>(sender_object);
const QList<QTreeWidget*> children = ui->TreeScrollAreaContents->findChildren<QTreeWidget*>(QRegularExpression(), Qt::FindDirectChildrenOnly);
for(QList<QTreeWidget*>::const_iterator it = children.begin(); it != children.end(); it++)
{
QTreeWidget* child_tree = *it;
if(sender_tree != child_tree)
{
child_tree->clearSelection();
child_tree->clearFocus();
}
}
}
}
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>400</width>
<height>176</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QScrollArea" name="TreeScrollArea">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<height>171</height>
</rect>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="TreeScrollAreaContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>399</width>
<height>169</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">#TreeScrollAreaContents {
background-color: #000000;
}</string>
</property>
<layout class="QGridLayout" name="TreeScrollAreaGridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTreeWidget" name="treeWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<column>
<property name="text">
<string>1</string>
</property>
</column>
<item>
<property name="text">
<string>Item 1</string>
</property>
<item>
<property name="text">
<string>Sub Item 1</string>
</property>
</item>
<item>
<property name="text">
<string>Sub Item 2</string>
</property>
</item>
<item>
<property name="text">
<string>Sub Item 3</string>
</property>
</item>
<item>
<property name="text">
<string>Sub Item 4</string>
</property>
</item>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QTreeWidget" name="treeWidget_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<column>
<property name="text">
<string>1</string>
</property>
</column>
<item>
<property name="text">
<string>Item 1</string>
</property>
<item>
<property name="text">
<string>Sub Item 1</string>
</property>
</item>
<item>
<property name="text">
<string>Sub Item 2</string>
</property>
</item>
<item>
<property name="text">
<string>Sub Item 3</string>
</property>
</item>
<item>
<property name="text">
<string>Sub Item 4</string>
</property>
</item>
</item>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
One thing is the currentItem and another is the selected items, instead of using the currentItemChanged signal you must use the signal itemSelectionChanged. When using clearSelection() the respective QTreeWidget will also emit the signal itemSelectionChanged and this could generate an infinite loop, the solution is to use blockSignals().
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTreeWidgetItem>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
void OnSelectedTreeValueChanged(); // remove arguments
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTreeWidget>
#include <QTreeWidgetItem>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
const QList<QTreeWidget*> childrens = ui->TreeScrollAreaContents->findChildren<QTreeWidget*>(QRegularExpression(), Qt::FindDirectChildrenOnly);
for(QTreeWidget* child_tree: childrens)
{
child_tree->expandAll();
child_tree->setItemsExpandable(false);
connect(child_tree, &QTreeWidget::itemSelectionChanged, this, &MainWindow::OnSelectedTreeValueChanged);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::OnSelectedTreeValueChanged()
{
QTreeWidget *sender_tree = qobject_cast<QTreeWidget *>(sender());
if(sender_tree->currentItem()->childCount() == 0)
{
const QList<QTreeWidget*> childrens = ui->TreeScrollAreaContents->findChildren<QTreeWidget*>(QRegularExpression(), Qt::FindDirectChildrenOnly);
for(QTreeWidget* child_tree: childrens)
{
if(sender_tree != child_tree)
{
child_tree->blockSignals(true);
child_tree->clearSelection();
child_tree->blockSignals(false);
}
}
}
}
Note:
I will explain why your method does not work, you are using the currentItem as a basic element of your algorithm, but a currentItem may be selected or no, clearSelection does not affect the currentItem.
I'm new to QT and now facing a problem with function QImage::setPixel and QPainter::drawPoint
I have mainwindow and a widget in it, called drawing area. The drawing area using layout with a label in it, which contains QImage converted to QPixmap. Unfortunately the functions I use to draw points give no result.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
area = new DrawingArea(this);
area->setGeometry(0,0,this->width(),this->height()/2);
area->show();
button = new QPushButton("Draw", this);
int bwidth = 100, bheight = 50;
button->setGeometry(200, 300, bwidth, bheight);
connect(button, SIGNAL(clicked(bool)), this, SLOT(getPoint()));
}
MainWindow::~MainWindow()
{
delete ui;
delete button;
delete area;
}
void MainWindow::getPoint(){
area->clearPoints();
area->makePoint(ui->textEdit->toPlainText().toInt(), ui->textEdit_2-
>toPlainText().toInt());
area->makePoint(ui->textEdit_3->toPlainText().toInt(), ui->textEdit_4-
>toPlainText().toInt());
area->makePoint(ui->textEdit_5->toPlainText().toInt(), ui->textEdit_6-
>toPlainText().toInt());
area->showPoints();
}
DrawinArea.cpp
#include "drawingarea.h"
#include <QHBoxLayout>
#include <QPen>
#include <QPainter>
DrawingArea::DrawingArea(QWidget *parent) : QWidget(parent)
{
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
canvas = new QImage(600, 500, QImage::Format_RGB32);
QRgb val = qRgb(189,149,39);
canvas->fill(Qt::gray);
canvas->setPixel(4,4,val);
canvas->setPixel(5,4,val);
imgDisplayer = new QLabel;
imgDisplayer->setPixmap(QPixmap::fromImage(*canvas));
displayer = new QLabel;
auto *layout = new QHBoxLayout(this);
layout->addWidget(imgDisplayer);
layout->addWidget(displayer);
}
void DrawingArea::paintEvent(QPaintEvent * /* event */){
//
}
void DrawingArea::clearPoints(){
points.clear();
}
void DrawingArea::makePoint(int x, int y){
Point *temp = new Point(x,y);
points.push_back(*temp);
free(temp);
}
void DrawingArea::showPoints(){
displayer->clear();
QPainter painter(canvas);
QPen pen;
pen.setWidth(1);
pen.setColor(Qt::red);
painter.setBrush(Qt::NoBrush);
painter.setPen(pen);
painter.end();
QString text;
for(size_t i = 0; i < points.size();i++){
text+= ("P" + QString::number(i) + " (X: " +
QString::number(points[i].x) +
"; Y: " + QString::number(points[i].y) + ");\n");
painter.drawPoint(points[i].x, points[i].y);
}
imgDisplayer->setPixmap(QPixmap::fromImage(*canvas));
displayer->setText(text);
displayer->setGeometry(300, 80, 100,100);
displayer->show();
imgDisplayer->show();
}
DrawingArea::~DrawingArea(){
delete canvas;
delete displayer;
delete imgDisplayer;
}
Here is a minimal example. Hope that helps :)
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QImage>
#include <QPainter>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->drawButton, &QPushButton::clicked, [=](){ // Lambda to keep example small. You may also just have a own method
auto x = ui->xLineEdit->text().toInt();
auto y = ui->yLineEdit->text().toInt();
const QPixmap *pixmap = ui->imageLabel->pixmap();
QImage image(QSize(600, 400), QImage::Format_RGB32);
if (pixmap) {
image = pixmap->toImage();
} else {
image.fill(Qt::gray);
}
QPainter painter(&image);
auto pen = painter.pen();
pen.setColor(Qt::red);
pen.setWidth(5);
painter.setPen(pen);
painter.drawPoint(x, y);
ui->imageLabel->setPixmap(QPixmap::fromImage(image));
ui->textLabel->setText(ui->textLabel->text().append("\nP(%1,%2)").arg(QString::number(x), QString::number(y)));
});
}
MainWindow::~MainWindow()
{
delete ui;
}
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>521</width>
<height>450</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="imageLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="textLabel">
<property name="text">
<string>Points:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>y:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="yLineEdit"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="xLineEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>x:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="drawButton">
<property name="text">
<string>Draw</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>521</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>
Best regards
I am making a math application that will be used by kids to learn basic math skills. So far I have the title label re-sizing, and staying a certain distance from the top, but since Qt's origin is in the top-left, I couldn't line up the bottom start button. Any help of suggestion are greatly appreciated, and thank you!
Here is how far the start label should be off of the bottom:
Here is what happens when I re-size too far widthwize:
Chalkboard.cpp:
#include "chalkboard.h"
#include "ui_chalkboard.h"
Chalkboard::Chalkboard(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Chalkboard)
{
ui->setupUi(this);
//setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
id = QFontDatabase::addApplicationFont(":/fonts/chawp.ttf");
family = QFontDatabase::applicationFontFamilies(id).at(0);
chawp = family;
setFont(chawp);
scene = new QGraphicsScene(100, 100, 100, 100);
ui->graphicsView->setScene(scene);
image = new QImage(":/images/depositphotos_40177799-Seamless-Chalkboard-Texture.jpg");
brush = new QBrush(*image);
ui->graphicsView->setBackgroundBrush(*brush);
titleEffect = new QGraphicsDropShadowEffect();
titleEffect->setBlurRadius(10);
titleEffect->setColor(QColor("#e0dbd1"));
titleEffect->setXOffset(0);
titleEffect->setYOffset(0);
startEffect = new QGraphicsDropShadowEffect();
startEffect->setBlurRadius(10);
startEffect->setColor(QColor("#e0dbd1"));
startEffect->setXOffset(0);
startEffect->setYOffset(0);
ui->labelTitle->setStyleSheet("color: #e0dbd1;font: url(:/font/chawp.ttf);");
ui->labelStart->setStyleSheet("color: #e0dbd1;font: url(:/font/chawp.ttf);");
ui->labelTitle->setGraphicsEffect(titleEffect);
ui->labelStart->setGraphicsEffect(startEffect);
}
Chalkboard::~Chalkboard()
{
delete ui;
}
void Chalkboard::resizeEvent(QResizeEvent *event)
{
QFontMetrics temp(chawp);
if (windowState() != Qt::WindowFullScreen)
{
setMaximumSize(1920, 1080);
}
QFont temp1(chawp);
QFont temp2(chawp);
temp1.setPixelSize(width()/10);
temp2.setPixelSize(width()/15);
ui->graphicsView->move(0, 0);
ui->graphicsView->resize(width(), height());
ui->labelTitle->resize(width(), height());
ui->labelTitle->move(0, 15);
ui->labelTitle->setFont(temp1);
//My failed attempt at it:
if (height()/5 < 75)
{
ui->labelStart->resize(width(), height());
ui->labelStart->move(0, height() - (height() / 5));
ui->labelStart->setFont(temp2);
}
}
Main.cpp:
#include "chalkboard.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Chalkboard w;
w.show();
return a.exec();
}
Chalkboard.h:
#ifndef CHALKBOARD_H
#define CHALKBOARD_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QFontDatabase>
#include <QDebug>
#include <QGraphicsDropShadowEffect>
namespace Ui {
class Chalkboard;
}
class Chalkboard : public QMainWindow
{
Q_OBJECT
public:
explicit Chalkboard(QWidget *parent = 0);
~Chalkboard();
public slots:
void resizeEvent(QResizeEvent* event);
private:
QGraphicsDropShadowEffect * titleEffect;
QGraphicsDropShadowEffect * startEffect;
QFont chawp;
QGraphicsScene *scene;
QString family;
int id;
QImage *image;
QBrush *brush;
Ui::Chalkboard *ui;
};
#endif // CHALKBOARD_H
Chalkboard.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Chalkboard</class>
<widget class="QMainWindow" name="Chalkboard">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>644</width>
<height>468</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>644</width>
<height>468</height>
</size>
</property>
<property name="windowTitle">
<string>Chalkboard</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>61</width>
<height>71</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="labelStart">
<property name="geometry">
<rect>
<x>120</x>
<y>290</y>
<width>311</width>
<height>131</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>35</pointsize>
</font>
</property>
<property name="text">
<string>Start</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
<widget class="QLabel" name="labelTitle">
<property name="geometry">
<rect>
<x>100</x>
<y>50</y>
<width>391</width>
<height>151</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>50</pointsize>
</font>
</property>
<property name="text">
<string>Chalkboard</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>40</x>
<y>220</y>
<width>131</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resource.qrc">
<normaloff>:/images/liberty-technology-arrow-1.png</normaloff>:/images/liberty-technology-arrow-1.png</iconset>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>444</x>
<y>200</y>
<width>111</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resource.qrc">
<normaloff>:/images/liberty-technology-arrow-2.png</normaloff>:/images/liberty-technology-arrow-2.png</iconset>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="resource.qrc"/>
</resources>
<connections/>
</ui>
I finally solved this by simply setting the QLabel's Y-Axis to (height()-(ui->pushButtonStart->height()))
Another solution:
Create a QFrame widget and put your labels and buttons inside, together with the necessary layouts and spacers.
In your resize event handler just set the proper width and height for this frame like you do for QGraphicsView (to occupy whole parent widget area).
I have modified your .ui file as a hint:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Chalkboard</class>
<widget class="QMainWindow" name="Chalkboard">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>644</width>
<height>468</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>644</width>
<height>468</height>
</size>
</property>
<property name="windowTitle">
<string>Chalkboard</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>311</width>
<height>341</height>
</rect>
</property>
</widget>
<widget class="QFrame" name="frame">
<property name="geometry">
<rect>
<x>210</x>
<y>10</y>
<width>349</width>
<height>401</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelTitle">
<property name="font">
<font>
<pointsize>50</pointsize>
</font>
</property>
<property name="text">
<string>Chalkboard</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/liberty-technology-arrow-1.png</normaloff>:/images/liberty-technology-arrow-1.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/liberty-technology-arrow-2.png</normaloff>:/images/liberty-technology-arrow-2.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="labelStart">
<property name="font">
<font>
<pointsize>35</pointsize>
</font>
</property>
<property name="text">
<string>Start</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</widget>
<zorder>graphicsView</zorder>
<zorder>frame</zorder>
<zorder>labelTitle</zorder>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="resource.qrc"/>
</resources>
<connections/>
</ui>