I've created a custom Widget: in the designer and promoted a QWidget to a TreeItem (my own). But when I run the code, I can't see the widget. The only way to see it is to use setFixedSize(100, 100). Even resize and setGeometrydon't work.
I want to be able to see my custom widget without giving it a fixed size.
TreeItem.h
#ifndef TREEITEM_H
#define TREEITEM_H
#include <QWidget>
#include <QRect>
class TreeItem : public QWidget
{
Q_OBJECT
public:
explicit TreeItem(QRect rect, QWidget *parent = nullptr);
virtual void paintEvent(QPaintEvent*);
signals:
public slots:
protected:
QRect m_rect;
QFont m_font;
};
#endif // TREEITEM_H
TreeItem.cpp
#include "treeitem.h"
TreeItem::TreeItem(QRect rect, QWidget *parent): QWidget(parent)
{
m_rect = rect;
m_font = QFont("Arrial", 20);
setFixedSize(100, 100); // doesn't show up without this line
}
void TreeItem::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.drawLine(0, 0, 100, 100);
}
Related
Problem
When QPainter is created after glClear the latter has no effect.
Description
I use Qt 5.7.1. I get same results with gcc on Linux and vc++ on Windows.
I have the following in a widget derived from QGLWidget:
void CanvasWidget::initializeGL()
{
qglClearColor(m_backgroundColor);
}
V1:
void CanvasWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
QPainter painter(this);
painter.drawLine(0, 0, 1000, 1000);
}
Produces:
V2:
void CanvasWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
}
Produces:
What I want is:
Which can be done with a hack:
void CanvasWidget::paintGL()
{
QPainter painter(this);
qglClearColor(m_backgroundColor);
glClear(GL_COLOR_BUFFER_BIT);
painter.drawLine(0, 0, 1000, 1000);
}
Question
What is going on? Why can't glClean and QPainter work together? Why can't I get it with V1?
Minimal Reproducible Example
main.cpp
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainwindow;
mainwindow.show();
return app.exec();
}
MainWindow.h
#pragma once
#include "CanvasWidget.h"
#include <QMainWindow>
#include <memory>
class MainWindow : public QMainWindow
{
public:
explicit MainWindow(QWidget *parent = 0);
MainWindow(const MainWindow &) = delete;
MainWindow & operator= (const MainWindow &) = delete;
virtual ~MainWindow() = default;
private:
std::unique_ptr<CanvasWidget> m_canvasWidget;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QHBoxLayout>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, m_canvasWidget(new CanvasWidget(parent))
{
setCentralWidget(m_canvasWidget.get());
}
CanvasWidget.h
#pragma once
#include <QGLWidget>
class CanvasWidget : public QGLWidget
{
Q_OBJECT
public:
CanvasWidget(QWidget* parent = 0, const QGLWidget* shareWidget = 0, Qt::WindowFlags f = 0);
private:
virtual void initializeGL() override;
virtual void paintGL() override;
private:
QColor m_backgroundColor;
};
CanvasWidget.cpp
#include "CanvasWidget.h"
#include <QMessageBox>
#include <QWheelEvent>
CanvasWidget::CanvasWidget(
QWidget* parent /*= 0*/,
const QGLWidget* shareWidget /*= 0*/,
Qt::WindowFlags f /*= 0 */)
: QGLWidget(parent, shareWidget, f)
, m_backgroundColor(0, 93, 196)
{}
void CanvasWidget::initializeGL()
{
qglClearColor(m_backgroundColor);
}
void CanvasWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
QPainter painter(this);
painter.drawLine(0, 0, 1000, 1000);
}
Adding setAutoFillBackground(false) in CanvasWidget constructor solves the problem.
All the credit goes to #G.M.
In Qt tutorial about overpainting OpenGL with QPainter it is stated:
When overpainting 2D content onto 3D content, we need to use a
QPainter and make OpenGL calls to achieve the desired effect. Since
QPainter itself uses OpenGL calls when used on a QGLWidget subclass,
we need to preserve the state of various OpenGL stacks when we perform
our own calls
So, looking at your code in V1 I suppose that QPainter sets its own clear color state, and if you don't set your glClearColor explicitly, you will get what QPainter object has set.
And I would also suggest you to use a tool like RenderDoc or gDebugger to trace GL commands of your app to see exactly what happens under the hood.
I'm in the process of transitioning from PyQt5 to Qt5 in C++ and I'm having a bit of a tough time. I created a simple UI that contains a Qwidget called logo. I'm trying to make this widget an SVG rendering widget with this code:
QSvgRenderer renderer(QString(":/LogoSVG.svg"));
QImage image(500, 200, QImage::Format_ARGB32);
image.fill(0x000000);
QPainter painter(&image);
renderer.render(&painter);
In Python, I'd create a simple widget class that renders the SVG then in the UI form loader class I'd do
self.logo = SVGRender(self)
I'm trying to do the same thing in C++ Qt, so here's what I have so far and it's returning the error error: cannot convert ‘logoW’ to ‘QWidget*’ in assignment
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
#include "ui_example.h"
class example : public QWidget
{
Q_OBJECT
public:
example(QWidget *parent = 0);
private:
Ui::example ui;
};
class logoW: public QWidget
{
Q_OBJECT
public:
logoW(QWidget *parent = 0);
};
#endif
example.cpp
#include <QtGui>
#include <QScreen>
#include <QApplication>
#include <QDesktopWidget>
#include <QCoreApplication>
#include <QSvgRenderer>
#include <QPainter>
#include <QImage>
#include <iostream>
#include "example.h"
using namespace std;
example::example(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
ui.logo = logoW(this)
}
logoW :: logoW(QWidget * parent = 0){
QSvgRenderer renderer(QString(":resources/LogoSvg.svg"));
QImage image(500, 200, QImage::Format_ARGB32);
image.fill(0xaaA08080);
QPainter painter(&image);
renderer.render(&painter);
}
Can someone show me what I'm doing wrong?
The variable ui.logo requires a pointer of the object, in your case it changes:
ui.logo = logoW(this);
to:
ui.logo = new logoW(this);
I also understand that you want to display the image in the logo widget. To do this you must implement the paintEvent method:
*.h
class logoW: public QWidget
{
Q_OBJECT
public:
logoW(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
};
*.cpp
logoW::logoW(QWidget *parent):QWidget(parent)
{
}
void logoW::paintEvent(QPaintEvent *event){
Q_UNUSED(event)
QSvgRenderer renderer(QString(":resources/LogoSvg.svg"));
QPainter painter(this);
renderer.render(&painter);
}
When i try to put QLabel in QWidget class its not work properly (no hover event or click event only the label pixmap is show) only the last instance work properly, when not use set parent, it create in new window for each label but its work correctly
this gif show the problem:
https://media.giphy.com/media/3o7TKKmZSISGXN4Opq/giphy.gif
this is QLabel subclass header:
#include <QObject>
#include <QLabel>
class myLabel : public QLabel
{
Q_OBJECT
public:
myLabel();
protected:
void mousePressEvent(QMouseEvent *);
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
signals :
void labelClicked();
void enterSignal();
void leaveEventSignal();
private:
};
this class to make a labelButton:
#include <QObject>
#include <QWidget>
#include "mylabel.h"
class labelButton : public QWidget
{
Q_OBJECT
public:
labelButton();
//some functions
private slots:
//slots
private:
//private member
};
and this the class that i want to use the labelButtons in:
#include <QWidget>
#include "labelbutton.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
labelButton *b_1, *b_2, *b_3;
};
here is widget.cpp:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
b_1 = new labelButton;
b_1->setParent(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
b_1->show();
//-----------------------
b_2 = new labelButton;
b_2->setParent(this);
b_2->moveButton(70, 200);
//some functions to initialize the labelButton
b_2->show();
//-----------------------
b_3 = new labelButton;
b_3->setParent(this);
b_3->moveButton(70, 300);
//some functions to initialize the labelButton
b_3->show();
}
here its work, the problem was in passing the parent
i made a function that take a widget and set buttons parent from the function value
b_1 = new labelButton;
//b_1->setParent(this);
b_1->setParentFunc(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
// b_1->show();
in labelButton:
void labelButton::setParentFunc(QWidget *p)
{
myParent = p;
}
mLabel_1->setParent(myParent); // myParent instead of this
I'm writing simple application by using QPixmap and QPainter. In my programm I need to load some images and resize them. I used QPixmap::scaled(), but images does not scaled. What I did wrong?
This is my code:
chesstile.cpp
#include "chesstile.h"
ChessTile::ChessTile(QWidget *parent) :
QLabel(parent)
{
}
void ChessTile::paintEvent(QPaintEvent *)
{
const QString &fileName = "images/white_king.png";
QPixmap bgPixmap(fileName);
bgPixmap.scaled(QSize(64, 64));
QPainter painter(this);
painter.drawPixmap(0, 0, bgPixmap);
}
chesstile.h
#ifndef CHESSTILE_H
#define CHESSTILE_H
#include <QLabel>
#include <QString>
#include <QPainter>
#include <QPixmap>
#include <QSize>
class ChessTile : public QLabel
{
Q_OBJECT
public:
ChessTile(QString fileName,
QString tileColor,
QWidget *parent = 0);
void paintEvent(QPaintEvent *);
private:
signals:
public slots:
};
#endif // CHESSTILE_H
You'll notice from the docs that the QPixmap::scaled member function is const - i.e. it doesn't change the object itself.
The scaled object is returned by that method, it doesn't change the original pixmap.
Try something like:
QPixmap bgPixmap(fileName);
QPixmap scaled = bgPixmap.scaled(QSize(64, 64));
QPainter painter(this);
painter.drawPixmap(0, 0, scaled)
I want my QGraphicsPixmapItem become selectable (i.e. clickable in more general way) on QGraphicScene but it doesn't. I'm actually modifying Qt's Diagram Scene sample, where QGraphicsItem's subclass is used and is selectable. I appreciate your help.
cpp code (partial):
#include <iostream>
#include <QtGui>
#include "overlayPixmapItem.h"
OverlayPixmapItem::OverlayPixmapItem(DiagramType diagramType, QMenu *contextMenu,
QPixmap img, QGraphicsItem *parent,
QGraphicsScene *scene)
: QGraphicsPixmapItem(img, parent), QObject()
{
myDiagramType = diagramType;
myContextMenu = contextMenu;
this->setAcceptsHoverEvents(true);
this->setAcceptHoverEvents(true); //
this->setAcceptedMouseButtons(Qt::LeftButton);
this->setAcceptedMouseButtons(Qt::RightButton);
this->acceptDrops();
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
}
:
header (partial):
#ifndef OVERLAYPIXMAPITEM_H
#define OVERLAYPIXMAPITEM_H
#include <QGraphicsPixmapItem>
#include <QList>
#include <QObject>
class QPixmap;
class QGraphicsItem;
class QGraphicsScene;
class QTextEdit;
class QGraphicsSceneMouseEvent;
class QMenu;
class QGraphicsSceneContextMenuEvent;
class QPainter;
class QStyleOptionGraphicsItem;
class QWidget;
class QPolygonF;
class OverlayPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
enum { Type = UserType + 15 };
enum DiagramType { Crosshair };
OverlayPixmapItem(DiagramType diagramType, QMenu *contextMenu,
QPixmap img, QGraphicsItem *parent = 0, QGraphicsScene *scene = 0);
DiagramType diagramType() const { return myDiagramType; }
QPolygonF polygon() const { return myPolygon; }
int type() const { return Type;}
protected:
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void hoverEnterEvent ( QGraphicsSceneHoverEvent * event );
void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event );
public: signals:
void mouseHoveredOnElem(OverlayPixmapItem *i);
void mouseHoveredOutOfElem(OverlayPixmapItem *i);
private:
DiagramType myDiagramType;
QPolygonF myPolygon;
QMenu *myContextMenu;
};
#endif // OVERLAYPIXMAPITEM_H
As pointed out in my first comment, you call setAcceptedMouseButtons() method twice. While the first call actually set the correct button to be accepted, the second call make this setting lost.
To accept both buttons on this item, you have to combine Qt MouseButtons flags, this way :
item->setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton) ;