Qt Custom ProgressBar can't refresh (paintEvent) - qt

i've created a custom progress bar, but when i call the SetValue() method the paintEvent method (overrided) is not called, so the progress bar show just the veryfirst value.
This is the Header grafica_progressbar.h
#ifndef GRAFICA_PROGRESSBAR_H
#define GRAFICA_PROGRESSBAR_H
#include <QWidget>
#include <QProgressBar>
#include <QPaintEvent>
#include <QPainter>
#include <QBrush>
#include <QStyle>
#include <QPen>
#include <QColor>
class grafica_ProgressBar : public QProgressBar
{
Q_OBJECT
public:
grafica_ProgressBar();
protected:
void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE;
};
#endif // GRAFICA_PROGRESSBAR_H
and this is the cpp grafica_progressbar.cpp
#include "grafica_progressbar.h"
grafica_ProgressBar::grafica_ProgressBar()
{
}
void grafica_ProgressBar::paintEvent(QPaintEvent *)
{
int tmpValue = value();
int TopPos = QStyle::sliderPositionFromValue(minimum(), maximum(), tmpValue, width());
QPainter p(this);
if (tmpValue<maximum()*0.85)
{
p.setPen(Qt::green);
p.setBrush(QBrush(Qt::green));
}
else
{
p.setPen(QColor(255,51,51));
p.setBrush(QColor(255,51,51));
}
p.drawRect(0,0,TopPos,height());
p.setPen(Qt::gray);
p.setBrush(QBrush(Qt::lightGray));
p.drawRect(TopPos, 0, width(), height()); //riempio tutto il resto di grigio
p.setPen(Qt::black);
p.setBrush(QBrush(Qt::black));
p.drawText(0,0, width(), height(), Qt::AlignCenter, QString::number(tmpValue ) + " bar");
}
and this is the first call into the userinterface costructor
TestProgres = new grafica_ProgressBar();
ui->gridLayout->addWidget(TestProgres);
TestProgres->setMaximum(400);
TestProgres->setValue(300);
if i try to call TestProgres->setValue(200) inside a button, i can't see any refresh.
So, where's the problem?

The code starts to work after a "clean, rebuilt & run" operation.
I've edited the code just for showing the correct value.
Thanks to all!

Related

Crash when adding QGraphicsProxyWidget

I'm trying to have a QPushButton in my scene, but when I'm trying to add the QGraphicsProxyWidget to the scene, it crashes.
So here's the .cpp:
#include "upgradecromagnon.h"
#include "game.h"
#include <QGraphicsProxyWidget>
#include <qDebug>
extern Game *game;
UpgradeCromagnon::UpgradeCromagnon()
{
this->setRect(-50,0,150,50);
buttonAmelio = new QPushButton("salut");
teste();
}
void UpgradeCromagnon::teste()
{
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget();
proxy->setWidget(buttonAmelio);
scene()->addItem(proxy);
}
and its .h:
#ifndef UPGRADECROMAGNON_H
#define UPGRADECROMAGNON_H
#include <QPainter>
#include <QGraphicsRectItem>
#include <QPushButton>
class UpgradeCromagnon: public QGraphicsRectItem
{
public:
UpgradeCromagnon();
void teste();
private:
QPushButton *buttonAmelio;
};
#endif // UPGRADECROMAGNON_H
Your UpgradeCromagnon constructor calls UpgradeCromagnon::teste which, in turn, calls QGraphicsItem::scene. At that point QGraphicsItem::scene must return a null pointer since there's no possible way the UpgradeCromagnon instance can have been added to a QGraphicsScene before its contructor has completed (not according to the code you've provided at any rate).

'QMessageBox::critical' : none of the 4 overloads could convert all the argument types

I want to display an error message whenever my independent thread encounters the word "alert1" in a specific .txt file. But I get the above error inside the monitorForAlerts() inside mythread.cpp file. The line expectedly executes if I were to place it inside dialog.cpp. So I guess this is due to non-inheritance of this object. Can you please advise me how to solve this error for the given code?
Here is the code:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtCore>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
private:
Ui::Dialog *ui;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#include <QFile>
#include <Windows.h>
#include <QMessageBox>
#include <QTimer>
#define ALERTS_MESSAGE_STORAGE_PATH "E:\\QT1\\simpleGUIThread2\\simpleGUIThread2\\usbAlert.txt"
#define TIMER_VALUE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
void monitorForAlerts();
int exec();
public slots:
signals:
void testSignal(QString message);
public slots:
};
#endif // MYTHREAD_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->show();
}
void Dialog::on_pushButton_2_clicked()
{
ui->label->hide();
}
mythread.cpp
#include "mythread.h"
#include "dialog.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
monitorForAlerts();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::monitorForAlerts()
{
QString response = ALERTS_MESSAGE_STORAGE_PATH;
QFile resp(response);
resp.open(QIODevice::WriteOnly);
resp.close();
QFile resp1(response);
char buf[121];
char buf1[] = "alert1";
char buf2[] = "alert2";
resp1.open(QIODevice::ReadOnly);
while(resp1.size() == 0)
{
Sleep(3000);
}
qint64 lineLength = resp1.readLine(buf, sizeof(buf));
resp1.close();
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
}
if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
}
main.cpp
#include "dialog.h"
#include <QApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
w.show();
return a.exec();
}
LATEST UPDATE*********************************************************************
Hi Zlatomir,
I choose to take your 1st advice. I have created a signal that the thread will emit and connect it to a slot for QDialog. Please let me know if my understanding is correct, because I do not know where to implement the connect(), since the signal is declared in mythread.h and the slot in dialog.h. The connection type argument for connect is Qt::QueuedConnection, so that gui elements from another thread different than main-thread.
are NOT created. Is this statement correct? and where do I place this?
connect( mThread, SIGNAL(alertSignal(QString)), this, SLOT(alertSlot(QString)), Qt::QueuedConnection);
mythread.h
//....
signals:
void alertSignal(QString message);
//....
dialog.h
//....
public slots:
void alertSlot(QString message);
//....
mythread.cpp
//....
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
emit(alertSignal("alert1"));
}
else if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
emit(alertSignal("alert2"));
}
dialog.cpp
void Dialog::alertSlot(QString message)
{
if(strcmp(message, "alert1"))
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
else if(strcmp(message, "alert2"))
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
Now if this were correct, how do i implement the connect() and in which file?
The first argument is the problem, in your case this is not a good argument, because there this is a pointer to a MyThread instance, and MyThread is not a QWidget (is not derived from QWidget).
To solve this you can show the QMessageBox::critical from a slot in mainwindow (the Dialog class in your code, there you pass the instance of main-window that is a QWidget) and connect that slot with a signal that you emit from your thread, make sure that the connection type argument for connect is Qt::QueuedConnection, so that you don't try to create gui elements from another thread different than main-thread.
Another option would be to validate the data before you start the second thread and to tell
the user that he needs to provide the right files.
LE: Also check the QThread's documentation for the recommended way to use the class, now it's recommended not to derive from QThread.
LE2 - answer to the update
That connect can be made where ever you can have the two instances that you want to connect, in your case main.cpp is a good place to connect those (don't forget to fully qualify the name for connect: QObject::connect):
//...
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
QObject::connect( &mThread1, SIGNAL(alertSignal(QString)), &w, SLOT(alertSlot(QString)), Qt::QueuedConnection);
w.show();
//...

some error with mousepressevent()

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMouseEvent>
#include <QDebug>
#include "my_qlabel.h"
#include<QTimer>
int px;
int py;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tmrTimer = new QTimer(this);
connect(tmrTimer,SIGNAL(timeout()),this,SLOT(showthepositionofmouse()));
tmrTimer->start(20);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showthepositionofmouse()
{
ui->plainTextEdit->appendPlainText(QString(" x , y = ")+QString::number(px)+QString::number(py));
}
void my_qlabel::mousePressEvent(QMouseEvent *event)
{
if (event->button()==Qt::RightButton){
px = event->x();
py = event->y();
}
}
i Want to display the position of Mouse clicked
i use ui->plainTextEdit->appendPlainText(QString(" x , y = ")+QString::number(px)+QString::number(py)); to display this position. although i click mouse,it only show x,y = 0 0. why that?
The py and px that are accessed in my_qlabel::mousePressEvent, are member variables of my_qlabel and are not visible to MainWindow::showthepositionofmouse.
If you want them to be visible you should send them using a signal and slot.
http://qt-project.org/doc/qt-4.8/signalsandslots.html
Here is a way to implement it:
In my_qlabel.h have something like this:
class my_qlabel : public QLabel
{
Q_OBJECT
signals:
void right_click_xy(int x, int y);
// ...constructor and other functions
public slots:
void mousePressEvent(QMouseEvent *event)
{
int px, py;
if (event->button()==Qt::RightButton){
px = event->x();
py = event->y();
emit right_click_xy(px, py);
}
}
}
In mainwindow.h have something like this:
class MainWindow : public QMainWindow
{
Q_OBJECT
// ... constructor and other functions
public slots:
void on_display_click_xy(int px, int py)
{
qDebug() << "Received xy over signal slot:" << px << py;
ui->plainTextEdit->appendPlainText(QString(" x , y = ")+QString::number(px)+QString::number(py));
}
}
And inside your MainWindow constructor put the following:
QObject::connect(ui->my_qlabel_instance, SIGNAL(right_click_xy(int,int)),
this, SLOT(on_display_click_xy(int, int)));
Another alternate way of doing this, but is isn't as kosher, would be to drill down into your ui object and access px and py that way.
qDebug() << ui->my_qlabel_instance->py;
But this is not as elegant, and isn't signaled the same way.
Another idea to look into is to use a QPoint object instead of two ints.
Hope that helps.
The whole idea is bad, you must process this event within my_qlabel class via signals and slots, not outside of it. I would suggest something like this (emit signal with coordinates of mouse click):
Header my_qlabel.h:
#ifndef MY_QLABEL_H
#define MY_QLABEL_H
#include <QLabel>
#include <QPoint>
#include <QEvent>
class my_qlabel : public QLabel
{
Q_OBJECT
public:
my_qlabel( const QString & text="", QWidget * parent = 0 );
signals:
void clicked(QPoint pos);
protected:
void mouseReleaseEvent ( QMouseEvent * event );
};
#endif // MY_QLABEL
Source my_qlabel.cpp:
#include "my_qlabel.h"
#include <QMouseEvent>
my_qlabel::my_qlabel( const QString & text, QWidget * parent )
:QLabel(parent)
{
setText(text);
}
void my_qlabel::mouseReleaseEvent ( QMouseEvent * event )
{
emit clicked(event->pos());
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "my_qlabel.h"
#include <QtGui/QWidget>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void showthepositionofmouse(QPoint pos);
};
#endif // MAINWINDOW_H
and mainwindow.cpp:
#include "mainwindow.h"
#include <QDebug>
#include <QPoint>
#include <QHBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
my_qlabel* label=new my_qlabel("Text of my label",this);
label->setAlignment(Qt::AlignCenter);
QGridLayout *lay=new QGridLayout(this);
this->setLayout(lay);
lay->addWidget(label,0,0,1,1);
connect(label,SIGNAL(clicked(QPoint)),this,SLOT(showthepositionofmouse(QPoint)));
}
MainWindow::~MainWindow()
{
}
void MainWindow::showthepositionofmouse(QPoint pos)
{
qDebug()<< "Clicked, position="<<pos;
}

Qt - several QTextBlock inline

Is it possible to arrange several QTextBlocks in QTextDocument in one horizontal line?
I need to know which block of text was clicked and QTextBlock would be nice to use due to its method setUserState(int), which can be used to hold id of particular block. Are there better approaches?
Not sure if I got your question right, but I am taking a shot at it (some three years after the question was asked.....)
In principle you can put QTextBlocks in a horizontal line using a QTextTable. If you then create a class which inherits from QTextEdit you can catch the mouse events and find out which text block was clicked.
I post some code below where I have a very simply dialog that only has a textedit in it (of the derived class mentioned above). I create a table laying out three text blocks in a horizontal line and set their user state to the column number. Then I have the text edit class only with the overloaded mouseEvent method which only prints the userState of whatever text block it is in to the command line, just to show the principle.
Let me know if this is of any help or if misunderstood your question.
dialog.h
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include "ui_dialog.h"
class MyDialog : public QDialog, public Ui::Dialog
{
public:
MyDialog(QWidget * parent = 0, Qt::WindowFlags f = 0);
void createTable();
};
#endif
dialog.cpp
#include "dialog.h"
#include <QTextTable>
#include <QTextTableFormat>
MyDialog::MyDialog(QWidget * parent, Qt::WindowFlags f) :
QDialog(parent,f)
{
setupUi(this);
}
void MyDialog::createTable()
{
QTextCursor cursor = textEdit->textCursor();
QTextTableFormat tableFormat;
tableFormat.setCellPadding(40);
tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None);
QTextTable* table=cursor.insertTable(1,3,tableFormat);
for( int col = 0; col < table->columns(); ++col ) {
cursor = table->cellAt(0, col).firstCursorPosition();
cursor.insertBlock();
cursor.block().setUserState(col);
cursor.insertText(QString("Block in Column ")+QString::number(col));
}
}
mytextedit.h
#ifndef MYTEXTEDIT_H
#define MYTEXTEDIT_H
#include <QTextEdit>
class MyTextEdit : public QTextEdit
{
public:
MyTextEdit(QWidget * parent = 0);
void mousePressEvent(QMouseEvent *event);
};
#endif
mytextedit.cpp
#include "mytextedit.h"
#include <QMouseEvent>
#include <QTextBlock>
#include <QtCore>
MyTextEdit::MyTextEdit(QWidget * parent) :
QTextEdit(parent)
{
}
void MyTextEdit::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton) {
qDebug() << this->cursorForPosition(event->pos()).block().userState();
}
}
main.cpp (just for completeness)
#include <QApplication>
#include "dialog.h"
int main(int argc, char** argv)
{
QApplication app(argc,argv);
MyDialog dialog;
dialog.show();
dialog.createTable();
return app.exec();
}

Connecting signals and slots in a QTextEdit subclass?

I derived a class from QTextEdit and use it as a "logbook". I equipped it with a slot to receive log-messages.
class CLogbook : public QTextEdit
{
Q_OBJECT;
public:
void log(QString msg) {append(msg)};
public slots:
void recvLogSignal(const QString message)
{
append("hallo");
std::cout << "signal received.\n";
log(message);
}
};
another class then emits a signal like this:
// in the header
signals:
void logMessage(const QString);
// in the implementation
emit logMessage("qt is cute");
std::cout << "if you can read this the logMessage was emitted\n";
and also i connect the signal to the slot
connect(tableeditor, SIGNAL(logMessage(const QString)), logbook, SLOT(recvLogSignal(const QString)));
However the message is never shown in the "logbook". What am i missing here?
SOLVED: The connect method was called after emitting the signal :-(
It is hard to see exactly what is wrong with your implementation without a full example. Sometimes signals or slots will fail if an object goes out of scope if it isn't initialized on the heap.
Another way that it could fail is if your QApplication hasn't reached the exec() call.
I haven't experimented with using const in signal and slot calls, and I haven't seen it in any examples before, so that could be causing the problem; but it seems to work fine in the example below.
Working Example With a Derived Class of QTextEdit
Here is a simple example I put together that does some basic logging with a push button and a line edit.
Here is the header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
//#include <QTextEdit>
#include "clogbook.h"
#include <QLineEdit>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget() {}
public slots:
void on_pushButton();
void on_lineEditReturn();
private:
CLogBook * text_edit_log;
QLineEdit * line_edit;
};
#endif // WIDGET_H
Here is the source:
#include "widget.h"
#include <QBoxLayout>
#include <QPushButton>
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QBoxLayout * box_layout = new QBoxLayout(QBoxLayout::TopToBottom);
text_edit_log = new CLogBook;
line_edit = new QLineEdit("Type Here and press Enter.");
QPushButton * push_button = new QPushButton("Click to Add To Log");
text_edit_log->setText("My Log Book");
box_layout->addWidget(text_edit_log);
box_layout->addWidget(line_edit);
box_layout->addWidget(push_button);
this->setLayout(box_layout);
QObject::connect(push_button, SIGNAL(clicked()), this, SLOT(on_pushButton()));
QObject::connect(line_edit, SIGNAL(returnPressed()), this, SLOT(on_lineEditReturn()));
}
void Widget::on_pushButton()
{
// text_edit_log->append("Push Button Logging Test");
text_edit_log->recvLogSignal("Push button test.");
}
void Widget::on_lineEditReturn()
{
// text_edit_log->append(line_edit->text());
text_edit_log->recvLogSignal(QString("LineEdit: ") + line_edit->text() );
line_edit->clear();
}
And here is the main:
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
And here is the CLogBook class:
#ifndef CLOGBOOK_H
#define CLOGBOOK_H
#include <QTextEdit>
#include <iostream>
class CLogBook : public QTextEdit
{
Q_OBJECT
public:
explicit CLogBook(QWidget *parent = 0) : QTextEdit(parent) { }
void log (QString msg) { append(msg); }
public slots:
void recvLogSignal(const QString message)
{
append("hallo");
std::cout << "signal received.\n" << std::endl;
log(message);
}
};
#endif // CLOGBOOK_H

Resources