QT C++ : Moving several labels at the same time - c++

I have been searching about Threads in QT and ways to process multiple events simultaneously according to their docs, only the main GUI thread can manage GUI related events. So my question is: Is it possible to move multiple labels or objects at the same time during execution? Im trying to create sort of a simulation proyect for school.
What I have right now is: it creates a label everytime I run the function so I need that label to move to a certain spot. Problem is since I need the function executed several times, when it executes again, the previous label stops and moves the new one. After it has completed it goes back to the previous.
Any help is appreciated thanks.
New to asking here and QT in general.
Edit:
Here is what I have of my function:
QLabel *cliente = new QLabel(this);
QPixmap pix("image.jpg");
cliente->setGeometry(10,50,128,128);
cliente->setPixmap(pix);
cliente->show();
int speed = 100;
while (cliente->x()<300){
QTime dieTime = QTime::currentTime().addMSecs(speed);
while (QTime::currentTime() < dieTime){
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
cliente->move(cliente->x()+10,cliente->y());
}

To handle the movement of widgets it is most advisable to use the QPropertyAnimation class, but if you want to handle parallel group animations it is opportune to use QParallelAnimationGroup as shown in the following example:
#include <QApplication>
#include <QLabel>
#include <QParallelAnimationGroup>
#include <QPropertyAnimation>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.resize(500, 550);
QParallelAnimationGroup group;
for(int i = 0; i < 10; i++){
QLabel *label = new QLabel(QString("label %1").arg(i), &w);
QPropertyAnimation *animation = new QPropertyAnimation(label, "pos");
animation->setDuration(1000);
animation->setStartValue(QPoint(50*i, 0));
animation->setEndValue(QPoint(50*i, 50*(i+1)));
group.addAnimation(animation);
}
group.start();
w.show();
return a.exec();
}
Output:

Related

How to make only one point label visible for QLineSeries/QXYSeries

I am using the qtcharts module of qt.
I am using c++ but it does not matter if the solution comes for another language (I will translate it afterwards).
Problem: I plot a bunch of QLineSeries in a QChart and I want to display the point labels only when hovering them.
I planned to use the signal QXYSeries::hovered() to detect when the mouse moves over a point (the same when the mouse moves away the point).
I know that there exists a member function QXYSeries::setPointLabelsVisible() but it makes visible all the points of the series.
I want to be able to display only one point at a time because the series are relatively large and displaying all the labels would degrade the readability.
Question: Is it possible to display only one point label for a QLineSeries ? If yes, how ?
I could not find such a feature anywhere in the Qt documentation.
Here is a baseline code sample to start with (for convenience):
Declaration:
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
};
Definition:
#include <QApplication>
#include <QLineSeries>
#include <QDateTimeAxis>
#include <QValueAxis>
#include <QChartView>
#include <QDateTime>
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
MainWindow::MainWindow()
{
setWindowTitle("QtCharts baseline");
resize(800, 500);
QtCharts::QChart * chart = new QtCharts::QChart;
chart->setTitle("Baseline sample");
chart->legend()->setAlignment(Qt::AlignRight);
QtCharts::QDateTimeAxis * time_axis = new QtCharts::QDateTimeAxis;
time_axis->setFormat("hh:mm:ss");
time_axis->setTitleText("Time");
time_axis->setTickCount(5);
QtCharts::QValueAxis * value_axis = new QtCharts::QValueAxis;
value_axis->setTitleText("Value (unit)");
value_axis->setTickCount(6);
chart->addAxis(time_axis, Qt::AlignBottom);
chart->addAxis(value_axis, Qt::AlignLeft);
QtCharts::QLineSeries * ls = new QtCharts::QLineSeries;
ls->setName("Test series");
ls->setPointsVisible(true);
//ls->setPointLabelsVisible(true);
QDateTime dt = QDateTime::currentDateTime();
ls->append(dt.toMSecsSinceEpoch(), -10);
ls->append(dt.addSecs(1).toMSecsSinceEpoch(), 8);
ls->append(dt.addSecs(2).toMSecsSinceEpoch(), 27);
ls->append(dt.addSecs(3).toMSecsSinceEpoch(), 12);
ls->append(dt.addSecs(4).toMSecsSinceEpoch(), 42);
chart->addSeries(ls);
ls->attachAxis(time_axis);
ls->attachAxis(value_axis);
QtCharts::QChartView * view = new QtCharts::QChartView;
view->setChart(chart);
this->setCentralWidget(view);
}
One technique you could try is making a "shadow" copy of the line series with just the one or few points you need, sitting on top of the actual data line. Draw with a transparent pen so the line doesn't show up but set the labels to be visible. You can add/remove/change points to the shadow copy of the line series, and only the labels you want drawn can be added to the series. The link shows one
example of the technique.

Per axis grid properties (color), how it works?

From this source code:
#include "mainwindow.h"
#include <Q3DScatter>
using namespace QtDataVisualization;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
Q3DScatter *graph = new Q3DScatter;
QWidget *widget = QWidget::createWindowContainer(graph);
setCentralWidget(widget);
}
MainWindow::~MainWindow() {}
I get:
See that wall directly in front, its grayed (can I describe it this way?) if compared to the other walls. How can I tweak grid lines that way? I mean just one wall.
Basically, you can change the color of the grid-line with the following code.
#include <QApplication>
#include <QtDataVisualization/Q3DScatter>
#include <QtDataVisualization/Q3DLight>
#include <QtDataVisualization/Q3DTheme>
#include <QDebug>
#include <QTimer>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
auto scatter = new QtDataVisualization::Q3DScatter;
auto widget=QWidget::createWindowContainer(scatter);
widget->show();
scatter->activeTheme()->setType(QtDataVisualization::Q3DTheme::ThemeQt);
scatter->activeTheme()->setGridLineColor(QColor("red"));
auto light = scatter->scene()->activeLight();
auto camera = scatter->scene()->activeCamera();
int counter = 0;
QTimer timer;
timer.start(1 / 60);
QObject::connect(&timer, &QTimer::timeout, [&]() {
camera->setXRotation(counter++/60);
});
return a.exec();
}
Still, there seems to be no effect on how the grid-lines are rendered. I think this is do to the lighting of the 3D scene and of course of the camera position.
My small example program rotates the camera of the scene and therefore also the lighting of the grid-lines changes.
I think, there is little you can do here, as the interfaces doesn't allow you to change the shader code of the grid-lines.
Solution might be to add a custom 3d item, set a mesh and texture color. Resize the item to look like a grid axis and set the position. Repeat the idea for as many axis lines it is required.
Wondering if there is a (better) alternative approach.

QLineSeries does not show up when working with numbers < 1e-14

When graphing a line series within a small range using QtChart library (for example, between 0 and 1e-15), the line series seemingly does not get rendered. Using larger numbers with the same exact code works perfectly.
I've tried boiling down my code to be as simple as possible, to find any mistakes I was making, but I cannot find any. I suspect this may be a bug in Qt, but I'm posting here in case I missed something before I file a bug report.
I've also failed to find any information online about people experiencing similar bugs, but that may just be an indication that my google-fu is weak.
I originally encountered this bug using PyQt5, but have recreated it in C++ to ensure it was not a PyQt5 specific bug.
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QLegend>
#include <QtCharts/QValueAxis>
QT_CHARTS_USE_NAMESPACE
#define FACTOR 1e-13
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineSeries *lineseries = new QLineSeries();
lineseries->setName("series");
lineseries->setUseOpenGL(true);
for (double i = 0.0; i < 10.0; i += 1.0)
lineseries->append(QPointF(i*FACTOR, i * FACTOR));
QChart *chart = new QChart();
chart->addSeries(lineseries);
chart->setTitle("Line example");
QValueAxis *axisX = new QValueAxis();
chart->setAxisX(axisX, lineseries);
QValueAxis *axisY = new QValueAxis();
chart->setAxisY(axisY, lineseries);
axisY->setRange(0.0, 9.0*FACTOR);
axisX->setLabelFormat("%.3E");
axisY->setLabelFormat("%.3E");
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignBottom);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(840, 900);
window.show();
return a.exec();
}
Running the code attached, I would expect to observe a linear line series rendered in the plot, but I see nothing rendered.
Modifying the FACTOR constant to something >= 1e-12 will make the line series display properly.

How to make bullet points bigger in password mode for QLineEdit?

I have a QLineEdit to which I set the echoMode to QLineEdit::Password like this:
myLineEdit->setEchoMode(QLineEdit::Password);
The bullets are shown, but they are too small for the purpose of my application:
I need to make them bigger like this:
I have tried to increase the font size using a stylesheet like that:
myLineEdit->setStyleSheet("QLineEdit { font-size: 20px; }");
This indeed makes the bullets bigger, but the text gets bigger as well.
How to increase the size of bullet points preserving the size of the text?
You can set a unicode character that shows a larger circle through lineedit-password-character:
#include <QApplication>
#include <QFormLayout>
#include <QLineEdit>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
auto lay = new QFormLayout(&w);
QLineEdit *normal_le = new QLineEdit;
normal_le->setEchoMode(QLineEdit::Password);
normal_le->setText("Pass");
lay->addRow("Normal: ", normal_le);
for(int i: {9210, 9679, 9899, 11044}){
QLineEdit *le = new QLineEdit;
le->setEchoMode(QLineEdit::Password);
le->setText("Pass");
le->setStyleSheet(QString("QLineEdit[echoMode=\"2\"]{lineedit-password-character: %1}").arg(i));
lay->addRow(QString::number(i), le);
}
w.show();
return a.exec();
}

How to check which image is set in my QLabel?

I have a Qt application where I need to show a blinking LED and for that I need to use some png image of off and on led.I created a Qlabel and used setstylesheet to display the image. I created a timer and connected the signal to a slot. Now the problem is how do I know if the current displayed image is OFF led or ON led.
I have many led in GUI so is there any better way to check this?
Don't bother trying to compare the image, just store a variable of the state of the LED. When the timer triggers you change the state of the variable and set the QImage accordingly.
// assuming a boolean variable
var = !var;
if(var)
label->setImage(":/images/imageOn");
else
label->setImage(":/images/imageOff");
This assumes the images imageOn and imageOff have been added to a Qt resource file and are under an 'images' prefix.
It is good practise to separate logic from its visual representation.
You can leverage the property mechanism to store the index of the next image to be used. A QLabel is-a QObject. Objects can have arbitrary properties assigned to them.
You also don't need to use style sheets to set image on a label. It's a premature pessimization because the stylesheet needs to be parsed every time you set it. If you're not using stylesheets for other purposes, to set an image on a label simply use setPixmap.
For example (Qt 5, C++11):
#include <QApplication>
#include <QTimer>
#include <QLabel>
#include <QImage>
#include <QPainter>
void blink(QLabel * label, const QList<QImage> & images)
{
const char * const prop = "imageIndex";
Q_ASSERT(!images.isEmpty());
if (label->property(prop).isNull()) {
// We're setting the image for the first time
label->setProperty(prop, images.size());
}
int i = (label->property(prop).toInt() + 1) % images.size();
label->setPixmap(QPixmap::fromImage(images[i]));
label->setProperty(prop, i);
}
QImage textImage(const QString & text, int size = 64)
{
QImage image(size, size, QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter p(&image);
p.setFont(QFont("helvetica", 20));
QTextOption opt;
opt.setAlignment(Qt::AlignCenter);
p.drawText(image.rect(), text, opt);
return image;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QList<QImage> images;
QLabel label;
QTimer timer;
images << textImage("0") << textImage("1") << textImage("2") << textImage("3");
blink(&label, images);
timer.start(250);
QObject::connect(&timer, &QTimer::timeout, [&]{ blink(&label, images); });
label.show();
return a.exec();
}