Image not displaying using QPainter drawImage - qt

I have an QFrame within a QWidget, in my application. When I try to draw a draw a image within the QFrame, the image is inserted only when coordinates are (0,0) and if they are something like (100,100) the image is not drawn. I created a new class for the frame and implemented paintEvent(QPaintEvent *p) in it. Is there any thing I am doing here ?
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QFrame>
#include <QPainter>
#include "frame.h"
class frame;
namespace Ui {
class Widget;
}
class Widget : public QFrame
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
frame * f;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QFrame(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
f = new frame(ui->frame);
f->show();
}
Widget::~Widget()
{
delete ui;
}
frame.h
#ifndef FRAME_H
#define FRAME_H
#include <QObject>
#include <QWidget>
#include <QPainter>
class frame : public QWidget
{
Q_OBJECT
public:
explicit frame(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *p);
signals:
public slots:
};
#endif // FRAME_H
frame.cpp
#include "frame.h"
frame::frame(QWidget *parent) : QWidget(parent)
{
}
void frame::paintEvent(QPaintEvent *p)
{
QPainter* pPainter = new QPainter(this);
QImage img(":/left.png");
Q_ASSERT(!img.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
pPainter->drawImage(target, img,source);
QWidget::paintEvent(p);
QWidget::update();
}
If I use QRect target(0,0,20,10) in the above code the image is drawn.
testImage.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = testImage
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp\
widget.cpp \
frame.cpp
HEADERS += widget.h \
frame.h
FORMS += widget.ui
RESOURCES += \
src.qrc
DISTFILES +=
I am being stuck in this one for a long time, any idea will be helpful. I have tried Qt verions 5.6 and 5.8, similar result. And the OS is Lubuntu. The image resolution is 20*10. Thanks.enter image description here

Try like this:
void frame::paintEvent(QPaintEvent *p){
QPainter lPainter(this);
QPixmap lPixmap(":/left.png");
Q_ASSERT(!lPixmap.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
lPainter->drawPixmap(target, lPixmap);
QWidget::paintEvent(p);}
remove update form painEvent and try to use pixmap.

I have found a solution, I have subclassed QgraphicsView and reimplemented paint method in it,
void graphicsView::paintEvent(QPaintEvent *e)
{
QGraphicsView::paintEvent(e);
QPainter pPainter(this->viewport());
QImage img(":/images/x.png");
Q_ASSERT(!img.isNull());
QRect target(300,230,20,10);
pPainter.drawImage(target, img);
}

Related

When moved a QDialog to another monitor and close it, the dialog will be blank after reopened

Env: Win10+Qt5.12.3(msvc)
code:
pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test
TEMPLATE = app
SOURCES += \
dialog.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
dialog.h \
mainwindow.h
FORMS += \
dialog.ui \
mainwindow.ui
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDialog>
#include "dialog.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void slot_btn_clicked();
private:
Ui::MainWindow *ui;
Dialog *dialog;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
dialog = new Dialog(this);
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(slot_btn_clicked()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slot_btn_clicked()
{
dialog->exec();
}
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QCloseEvent>
#include <QShowEvent>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
protected:
void closeEvent(QCloseEvent *e);
public:
explicit Dialog(QWidget *parent = nullptr);
~Dialog();
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
QVBoxLayout *layout = new QVBoxLayout(this);
QLabel *label = new QLabel(this);
label->setText("this is a label");
layout->addWidget(label);
QPushButton *btnaccept= new QPushButton(this);
btnaccept->setText("accept");
connect(btnaccept, &QPushButton::clicked, this, [=](){accept();});
layout->addWidget(btnaccept);
QPushButton *btnclose= new QPushButton(this);
btnclose->setText("close");
connect(btnclose, &QPushButton::clicked, this, [=](){close();});
layout->addWidget(btnclose);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::closeEvent(QCloseEvent *e)
{
qDebug() << __FUNCTION__;
QDialog::closeEvent(e);
//e->ignore(); // if ignored close event, working well.
//accept();
}
demo code pack
Video presentation
I found that a method of closing QDialog will cause this situation: close button in title bar(top-right corner of the dialog), if closing it by reject(), accept(), close() everything is working correctly.
There is another question which is similar with mine, but I think the answer (resize the dialog manually) is not perfect, is there any another solution?

How to reuse the same window after clicking on other button?

I am trying to create an image viewer with slide show. When the user clicks on the play button, the viewer starts to show images. When the the user clicks on the stop button, the viewer stops to show images. After stopping, when the user clicks on the play button again, the viewer will continue to show the remaining images. My problem is that when the user clicks on the stop button and click on the play button again, I don't know how to reuse the same window created at the beginning to show the remaining images.
Button3 is the play button.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include "showpic.h"
#include <QBasicTimer>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_3_clicked();
void tick();
void on_pushButton_4_clicked();
private:
Ui::MainWindow *ui;
QFileSystemModel *model;
QString filesPath;
ShowPic *showpic;
QStringList filenames;
QStringList::const_iterator m_imageIt;
QTimer m_timer;
};
#endif // MAINWINDOW_H
showpic.h
#ifndef SHOWPIC_H
#define SHOWPIC_H
#include <QWidget>
namespace Ui {
class ShowPic;
}
class ShowPic : public QWidget
{
Q_OBJECT
public:
explicit ShowPic(QWidget *parent = 0);
~ShowPic();
private:
Ui::ShowPic *ui;
public:
void addPixmap(const QPixmap &pixmap);
};
#endif // SHOWPIC_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QFileDialog>
#include<QFileSystemModel>
#include<QStringList>
#include <QTreeView>
#include <QGraphicsScene>
#include <QTime>
#include <QDebug>
#include <iostream>
#include <QTimer>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
filenames.append("C:\\test\\image.jpg");
filenames.append("C:\\test\\apple.jpg");
filenames.append("C:\\test\\orange.jpg");
filenames.append("C:\\test\\lemon.jpg");
filenames.append("C:\\test\\grape.jpg");
m_timer.setInterval(1000);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::tick(){
showpic->addPixmap(*m_imageIt);
m_imageIt ++;
if(m_imageIt == filenames.end()){
m_timer.stop();
m_imageIt = filenames.begin();
}
}
void MainWindow::on_pushButton_3_clicked() //click on the play button
{
if(!filenames.isEmpty()){ // initial click
showpic = new ShowPic();
m_timer.start();
showpic->setWindowState(Qt::WindowMaximized);
showpic->show();
} else if( ) { // click on the play button again,
m_timer.start(); //???
showpic->setWindowState(Qt::WindowMaximized); //???
showpic->show(); //???
}
}
void MainWindow::on_pushButton_4_clicked() // click on the stop button
{
m_timer.stop();
}
showpic.cpp
#include "showpic.h"
#include "ui_showpic.h"
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
ui->graphicsView->setScene(new QGraphicsScene);
ui->horizontalLayout->addWidget(ui->graphicsView);
this->setLayout(ui->horizontalLayout);
}
ShowPic::~ShowPic()
{
delete ui;
}
void ShowPic::addPixmap(const QPixmap &pixmap){
ui->horizontalLayout->addWidget(ui->graphicsView);
this->setLayout(ui->horizontalLayout);
ui->graphicsView->setScene(new QGraphicsScene);
ui->graphicsView->scene()->addPixmap(pixmap);
ui->graphicsView->fitInView(ui->graphicsView->scene()->itemsBoundingRect() ,Qt::KeepAspectRatio);
}
Else part of on_pushButton_3_clicked won't run in any case because filenames is being filled when MainWindow created. In your code, you're creating new showpic in every click.
Firstly, set showpic to NULL in constructor of MainWindow;
showpic = NULL;
And change on_pushButton_3_clicked method like this;
void MainWindow::on_pushButton_3_clicked() //click on the play button
{
if(showpic == NULL){
showpic = new ShowPic();
}
if(!showpic->isVisible()){
showpic->setWindowState(Qt::WindowMaximized);
showpic->show();
}
m_timer.start();
}
Lastly, i don't have QT now, so my answer may contains typo/syntax error.
This works for me. I tested the scene clearing method, and it worked fine for me. But here I decided to just store the pointer to the QGraphicsPixmapItem as a member variable, and just set a new pixmap to it, instead of clearing the scene constantly. Seems more elegant like this to me.
#include <QtWidgets>
class SlideView : public QWidget
{
Q_OBJECT
public:
SlideView(QWidget *parent = nullptr) : QWidget(parent)
{
setLayout(new QHBoxLayout);
layout()->addWidget(&view);
view.setScene(new QGraphicsScene(this));
pixmap_item = new QGraphicsPixmapItem;
view.scene()->addItem(pixmap_item);
}
void setPixmap(const QPixmap &pixmap)
{
pixmap_item->setPixmap(pixmap);
view.fitInView(view.scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
}
private:
QGraphicsView view;
QGraphicsPixmapItem *pixmap_item = nullptr;
};
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = nullptr) : QWidget(parent)
{
slide_iterator = slides.begin();
setLayout(new QHBoxLayout);
QPushButton *play_button = new QPushButton("Play");
QPushButton *stop_button = new QPushButton("Stop");
layout()->addWidget(play_button);
layout()->addWidget(stop_button);
connect(play_button, &QPushButton::clicked, this, &MainWidget::play);
connect(stop_button, &QPushButton::clicked, this, &MainWidget::stop);
connect(&timer, &QTimer::timeout, this, &MainWidget::showNextSlide);
}
public slots:
void play() {timer.start(1000); view.showMaximized(); view.activateWindow();}
void stop() {timer.stop();}
void showNextSlide()
{
QPixmap pixmap(*slide_iterator);
view.setPixmap(pixmap);
slide_iterator++;
if(slide_iterator == slides.end())
slide_iterator = slides.begin();
}
private:
QTimer timer;
QStringList slides{"one.png", "two.png", "three.png"};
QStringList::const_iterator slide_iterator;
SlideView view;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
#include "main.moc"

Drag and drop issue in Qt

I overload dragEnterEvent() and dropEvent() in my MainWindow class, and call setAcceptDrops() in the constructor. While the running, I drag a .txt file in to the texteditor, but it's not showing the content of that .txt. Instead, it's show the path of that .txt. Please somebody help where I did wrong. Thanks.
//Header
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Blockquote
//Source
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDragEnterEvent>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QMimeData>
#include <QList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setAcceptDrops(true);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event){
if(event->mimeData()->hasUrls())
event->acceptProposedAction();
else event->ignore();
}
void MainWindow::dropEvent(QDropEvent *event){
const QMimeData *mimeData = event->mimeData();
if(mimeData->hasUrls()){
QList<QUrl> urlList = mimeData->urls();
QString fileName = urlList.at(0).toLocalFile();
if(! fileName.isEmpty()){
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly))return;
QTextStream in(&file);
ui->textEdit->setText(in.readAll());
}
}
}
You see this behavior because dropping is enabled on QTextEdit and the event is consumed there. (By default TextEdit drop copies filename into text area.)
In your constructor disable dropping on TextEdit by using
ui->textEdit->setAcceptDrops(false)
and then the event will be handled by the dropEvent method in MainWindow

How to make slot for multiple QPushButtons?

From Qvector is set the number of buttons and their names (text). After cliking on the button I need to reseave text on it and display in lineEdit.
The header file:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QWidget>
#include <QVector>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void Buttons(QVector<QString>&);
private:
QVector<QPushButton*>button;
QString mline;
QLineEdit *line;
QVBoxLayout *layout;
QAction *Clicked;
};
#endif // DIALOG_H
The source file:
#include "dialog.h"
Dialog::Dialog(QWidget *parent): QDialog(parent)
{
this->setFixedSize(this->minimumSize());
line = new QLineEdit(this);
layout = new QVBoxLayout(this);
layout->addWidget(line);
QVector<QString>v;
v.append("a");
v.append("b");
v.append("c");
v.append("5");
v.append("45");
Buttons(v);
for(int i=0;i<button.size();i++)
layout->addWidget(button[i]);
setLayout(layout);
}
Dialog::~Dialog(){}
void Dialog::Buttons(QVector<QString>&vec)
{
if(!button.isEmpty())
button.clear();
for(int i=0; i<vec.size();i++)
{
button.append(new QPushButton(this));
button[i]->setText(vec[i]);
button[i]->show();
}
}
For it I'm not using user interface (ui), and couldn't make slots for all the buttons. How can it be done?
You can use QButtonGroup to id the buttons and consolidate the signals from all the buttons to a single slot
Example
QButtonGroup myButtongroup;
connect(&myButtonGroup,SIGNAL(buttonClicked(QAbstractButton*),this, SLOT(myButtonClicked (QAbstractButton*)));
for(int i=0; i<vec.size();i++)
{
QString buttonName = vec[i];
myButtonGroup.addButton(new QPushButton(buttonName,this),i);
//Get the button using myButtonGroup.button(i) to add to your layout
// You can add the buttons to the layout right here to elimate one more loop
layout.addWidget(myButtonGroup.button(i));
}
//Slot for button clicked
void Dialog::myButtonClicked(QAbstractButton *myButton)
{
line->setText(myButton->text());// Adding the button name to line edit
}
For more QButtonGroup signals refer the documentation
You can use signal/slot in your case. The signal/slot is related to QObject. It does not matter whether you use QT Designer or not. In your code,
for(int i=0; i<vec.size();i++)
{
button.append(new QPushButton(this));
connect(button[i], SIGNAL( clicked() ), this, SLOT(OnButtonClicked()));
button[i]->setText(vec[i]);
button[i]->show();
}
Maintain a QList of QPushButton references that you add and use "signals and slots" to register the clicked() signal of each button to a single slot. Inside the function, iterate the QList of QPushButton by comparing with QObject::sender() and identify the source.
#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
class TestWidget: public QWidget
{
Q_OBJECT
private:
QLabel *label;
QVBoxLayout *mainLayout;
QList<QPushButton*> mButtonList;
public:
TestWidget(QWidget *parent=nullptr) : QWidget(parent)
{
mainLayout = new QVBoxLayout(this);
label = new QLabel;
mainLayout->addWidget(label);
this->setLayout(mainLayout);
}
void addButton(QString buttonName)
{
QPushButton *button = new QPushButton(buttonName);
QObject::connect(button, SIGNAL(clicked(bool)), this, SLOT(buttonClicked(bool)));
mButtonList.append(button);
mainLayout->addWidget(button);
}
public slots:
void buttonClicked(bool event)
{
Q_UNUSED(event)
static_cast<QPushButton*>(QObject::sender())->setFocus();
for (int i = 0; i < mButtonList.size(); ++i)
{
if (mButtonList.at(i) == sender())
{
label->setText(QString(mButtonList.at(i)->text()));
break;
}
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestWidget wid;
wid.addButton("First Button");
wid.addButton("Second Button");
wid.addButton("Third Button");
wid.addButton("Fourth Button");
wid.show();
return a.exec();
}
#include "main.moc"
The above sample code along with *.pro file is available in github

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;
}

Resources