I've been created a frameless window in Qt that have widgets and background. but i have a problem in that form, when i resize form all widgets resize good but background not
See this pic for demonstration
When no resize occured:
http://0000.2.img98.net/out.php/i20624_no-resize.jpg
when resize occured:
http://0000.2.img98.net/out.php/i20625_with-resize.jpg
and here is my code for creating Form:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QPushButton>
#include <QLabel>
#include <QComboBox>
#include <QPixmap>
#include <QVBoxLayout>
#include <QPainter>
#include <QMouseEvent>
#include <QtGui>
#include <QSizeGrip>
class MyWidget : public QWidget {
Q_OBJECT
private:
QPushButton* button;
QLabel* label;
QComboBox* combobox;
QPixmap pixmap;
public:
explicit MyWidget(QWidget *parent = 0) : QWidget(parent, Qt::FramelessWindowHint)
{
// Create some controls
button = new QPushButton();
label = new QLabel();
combobox = new QComboBox();
QVBoxLayout* l = new QVBoxLayout();
l->addWidget(button);
l->addWidget(label);
l->addWidget(combobox);
QSizeGrip *grip = new QSizeGrip(parent);
l->addWidget(grip, 0, Qt::AlignBottom | Qt::AlignRight);
setLayout(l);
resize (400, 500);
setAttribute(Qt::WA_TranslucentBackground); // enable translucent background
pixmap = QPixmap("./1.png");
}
protected:
virtual void paintEvent (QPaintEvent* event) {
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(0, 0, 0, 0));
QRect rec = pixmap.rect();
painter.drawRect(this->rect());
painter.drawPixmap(this->rect(), pixmap, rec);
}
private:
bool pressed;
QPoint mousePressPoint;
protected:
virtual void mousePressEvent ( QMouseEvent * event ) {
QWidget::mousePressEvent(event);
if (!pressed) {
pressed = true;
mousePressPoint = event->pos();
}
}
#endif // MYWIDGET_H
Since your controls are centered in the window but don't look like they are, it might indicate that there is a transparent border around the non-transparent part of the image you are using as background.
You can remove the transparency from the brush in paintEvent to confirm that, with, for example:
painter.setBrush(QColor(0, 0, 0, 255));
To be more clear, the problem is not in your code, but in the image: open the image with an editor, select only the non-transparent part, keep only that part by using the "cropping tool", and finally save the image.
Related
I am unable to change the icon's 'on' state color in Qt. I have the following test code:
header file:
#pragma once
#include <QtWidgets/QMainWindow>
#include <QApplication>
#include <QPushButton>
#include <QPainter>
#include <QIcon>
#include <QPixmap>
#include <QStyleFactory>
#include <QIconEngine>
#include "ui_mainwindow.h"
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
private:
Ui::MainWindowClass ui;
};
implementation file:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
{
qApp->setStyle(QStyleFactory::create("Fusion"));
ui.setupUi(this);
QWidgetList allWidgets = qApp->allWidgets();
for (QWidget* wid : allWidgets) {
QString str = wid->metaObject()->className();
if (str == "QPushButton") {
auto btn = dynamic_cast<QPushButton*>(wid);
if (!btn->icon().isNull()) {
QIcon btnIcon = btn->icon();
QPixmap pixOff = btnIcon.pixmap(QSize(1024, 1024));
QPixmap pixOn = btnIcon.pixmap(QSize(1024, 1024));
QPixmap pixDisOff = btnIcon.pixmap(QSize(1024, 1024));
QPixmap pixDisOn = btnIcon.pixmap(QSize(1024, 1024));
QPainter paintOff(&pixOff);
paintOff.setCompositionMode(QPainter::CompositionMode_SourceIn);
paintOff.fillRect(pixOff.rect(), Qt::green);
QPainter paintOn(&pixOn);
paintOn.setCompositionMode(QPainter::CompositionMode_SourceIn);
paintOn.fillRect(pixOn.rect(), Qt::red);
QPainter paintDisOff(&pixDisOff);
paintDisOff.setCompositionMode(QPainter::CompositionMode_SourceIn);
paintDisOff.fillRect(pixDisOff.rect(), Qt::yellow);
QPainter paintDisOn(&pixDisOn);
paintDisOn.setCompositionMode(QPainter::CompositionMode_SourceIn);
paintDisOn.fillRect(pixDisOn.rect(), Qt::blue);
btnIcon.addPixmap(pixOff, QIcon::Normal, QIcon::Off);
btnIcon.addPixmap(pixDisOff, QIcon::Disabled, QIcon::Off);
btnIcon.addPixmap(pixOff, QIcon::Active, QIcon::Off);
btnIcon.addPixmap(pixOff, QIcon::Selected, QIcon::Off);
btnIcon.addPixmap(pixOn, QIcon::Normal, QIcon::On);
btnIcon.addPixmap(pixDisOn, QIcon::Disabled, QIcon::On);
btnIcon.addPixmap(pixOn, QIcon::Active, QIcon::On);
btnIcon.addPixmap(pixOn, QIcon::Selected, QIcon::On);
btn->setIcon(btnIcon);
}
}
}
}
In my .ui file I add a few QPushButton and apply pixmaps as their icons:
From left to right: Disabled Button, Checkable Button, Non-Checkable Button.
These buttons are placed in a checkable QGroupBox so that I can enable/disable them simultaneously.
When I run my code this is how it appears (the color for disabled is yellow so it is not much visible):
Here the color for the middle QPushButton should be Qt::red since it is in checked (i.e. QIcon::On) state, but it is not red.
When I uncheck the groupbox, all the buttons becomes disabled and the icons change to QIcon::Disabled, QIcon::Off:
The QIcon::Disabled, QIcon::On color is Qt::blue, and the middle button is in checked and disabled state, which means it should be blue but it is not.
The icons never change color to QIcon::Normal, QIcon::On or any other QIcon::On state. This means that the QIcon::Off state color is being applied correctly, but the QIcon::On state color is not being applied. Any ideas on how to solve this issue?
Preparing a minimal and reproducible example is always the right approach to solving the problem. Here is one that I have written for you and it is working:
#include <QApplication>
#include <QBoxLayout>
#include <QPushButton>
#include <QPainter>
class MainWindow : public QWidget
{
public:
MainWindow(QWidget *parent = nullptr) : QWidget(parent)
{
auto *l = new QVBoxLayout(this);
auto *button = new QPushButton(tr("Click Me"), this);
QPixmap pixOff(":/pix/images/save.png");
QPixmap pixOn(pixOff);
QPainter painter;
painter.begin(&pixOn);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(pixOn.rect(), Qt::red);
painter.end();
painter.begin(&pixOff);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(pixOff.rect(), Qt::green);
painter.end();
QIcon icon;
icon.addPixmap(pixOff, QIcon::Normal, QIcon::Off);
icon.addPixmap(pixOn, QIcon::Normal, QIcon::On);
button->setIcon(icon);
button->setCheckable(true);
button->setChecked(true);
l->addWidget(button);
l->addStretch();
resize(200, 100);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Note: The example uses a 16x16 png-image from the resources. You should substitute it with your own image.
The example produces the following result:
I have an application which shows some images in a grid and rest of the widgets in their respective positions. Something like this
Drawing inspiration from this i managed to solve keeping the aspect ratio of an image while resizing.
What are the issues:
The QLabel widgets(image widgets) overlap if QMainWindow is shrinked. Check the image below
The whole application is apparently not suited for different screens. Running this application on a laptop, layout is completely messed up.
What have i done:
Here is the MVCE code i have created
//ImageWidget.h
#ifndef IMAGEWIDGET_H
#define IMAGEWIDGET_H
#include <QLabel>
#include <QResizeEvent>
#include <QWidget>
class ImageWidget : public QLabel
{
Q_OBJECT
public:
explicit ImageWidget(QWidget* parent = nullptr);
virtual QSize sizeHint() const;
QPixmap scaledPixmap() const;
virtual int widthForHeight(int height) const;
public slots:
void setPixmap ( const QPixmap& p);
void resizeEvent(QResizeEvent* ev);
private:
QPixmap pix;
};
#endif // IMAGEWIDGET_H
ImageWidget.cpp
#include "imagewidget.h"
ImageWidget::ImageWidget(QWidget* parent) :
QLabel(parent)
{
setStyleSheet("QLabel{margin-left: 10px; border-radius: 25px; background: white; color: #4A0C46;}");
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setWidthForHeight(true);
setSizePolicy(sizePolicy);
setMinimumSize(sizeHint());
}
void ImageWidget::setPixmap (const QPixmap& p)
{
pix = p;
QLabel::setPixmap(scaledPixmap());
}
/* virtual */ int ImageWidget::widthForHeight(int height) const
{
return pix.isNull() ? height * pix.height() / pix.width() : height;
}
QSize ImageWidget::sizeHint() const
{
if(pix.width() != 0)
{
int h = this->height();
return QSize(widthForHeight(h), h);
}
else
{
return QSize(300, 300);
}
}
QPixmap ImageWidget::scaledPixmap() const
{
auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
scaled.setDevicePixelRatio(devicePixelRatioF());
return scaled;
}
void ImageWidget::resizeEvent(QResizeEvent* )
{
if (!pix.isNull())
{
QLabel::setPixmap(scaledPixmap());
}
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QTableWidget>
#include "imagewidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
virtual void resizeEvent(QResizeEvent* event) override;
private:
Ui::MainWindow *ui;
ImageWidget* lbl1;
ImageWidget* lbl2;
ImageWidget* lbl3;
ImageWidget* lbl4;
QPushButton* btn1;
QPushButton* btn2;
QPushButton* btn3;
QPushButton* btn4;
QTableWidget* tableWidget;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QTabWidget>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTabBar>
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout* mainLayout = new QVBoxLayout;
QVBoxLayout* tabLay = new QVBoxLayout;
QHBoxLayout* buttonLay = new QHBoxLayout;
QGridLayout* gridLay = new QGridLayout;
QHBoxLayout* dockLay = new QHBoxLayout;
btn1 = new QPushButton(this);
btn1->setText("Button1");
btn2 = new QPushButton(this);
btn2->setText("Button2");
btn3 = new QPushButton(this);
btn3->setText("Button3");
btn4 = new QPushButton(this);
btn4->setText("Button4");
QTabWidget* tabView = new QTabWidget(this);
tabView->addTab(new QWidget(), "Table");
tabView->setMinimumSize(500, 300);
tabView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
tableWidget = new QTableWidget(this);
tableWidget->setFixedHeight(200);
lbl1 = new ImageWidget(this);
lbl2 = new ImageWidget(this);
lbl3 = new ImageWidget(this);
lbl4 = new ImageWidget(this);
QPixmap lbl1Pix("1.png");
QPixmap lbl2Pix("2.png");
QPixmap lbl3Pix("3.png");
QPixmap lbl4Pix("4.png");
lbl1->setPixmap(lbl1Pix);
lbl1->show();
lbl2->setPixmap(lbl2Pix);
lbl2->show();
lbl3->setPixmap(lbl3Pix);
lbl3->show();
lbl4->setPixmap(lbl4Pix);
lbl4->show();
buttonLay->addWidget(btn1);
buttonLay->addWidget(btn2);
buttonLay->addWidget(btn3);
buttonLay->addWidget(btn4);
tabLay->addWidget(tabView);
gridLay->addWidget(lbl1, 0, 0);
gridLay->addWidget(lbl2, 0, 1);
gridLay->addWidget(lbl3, 1, 0);
gridLay->addWidget(lbl4, 1, 1);
dockLay->addLayout(gridLay);
dockLay->addLayout(tabLay);
mainLayout->addLayout(dockLay);
mainLayout->addLayout(buttonLay);
mainLayout->addWidget(tableWidget);
centralWidget()->setLayout(mainLayout);
setMinimumSize(200,200);
show();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resizeEvent(QResizeEvent * /*event*/)
{
// get label dimensions
int h = lbl1->height();
int w = lbl1->widthForHeight(h);
lbl1->setFixedWidth(w);
lbl2->setFixedWidth(w);
lbl3->setFixedWidth(w);
lbl4->setFixedWidth(w);
}
Main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
What do i want:
Set a minimum size to the whole application so that the imagewidgets do not overlap.
Make the whole app work on any PC or laptop screen with different resolutions.
The imagewidgets should take up available space while keeping the aspect ratio of the images and the QTabWidget on the right should have a fixed size.
Maybe there is an easy solution but i am bit confused with Qt Layout management system.
EDIT1: Added the image with overlapping widgets
Here is what I think is happening. When you set the pixmap like here:
QLabel::setPixmap(scaledPixmap());
The label will set the size of the images as the minimum size. And from that point on the label can not be resized any smaller.
The solution I have found around this is to set the following resize flags for the QLabel in the constructor:
QSizePolicy sizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
setSizePolicy(sizePolicy);
This way the QLabel will be resizable at all times. Or you might have to adapt the minimum width.
I am not sure if that is even it, but maybe it is a good start. Let me know what you make of this.
I create a dock widget in qt GUI and add a tree table widget on it. More than these in main menu I have others objects such QGraphicsView. In run time when I manually resize the dock's width, it pushes or pulls main window with it's objects and works good. when I resize dock in code, dock and it's objects overlap with main window's objects. how can I fix this? thank you for your attention.
in header file:
#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication.h"
#include <QtWidgets/QDockWidget>
#include <QtWidgets/QTreeWidget>
#include <QGraphicsView>
#include <QtWidgets/QPushButton>
class QtGuiApplication : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplicationClass ui;
QDockWidget *dockWidget;
QWidget *dockWidgetContents;
QTreeWidget *treeWidget;
QGraphicsView* qGraph;
QGraphicsScene* scene;
private slots:
void worker_fn();
};
in source file:
#include "QtGuiApplication.h"
QtGuiApplication::QtGuiApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
/// creat dock
dockWidget = new QDockWidget(this);
dockWidgetContents = new QWidget();
dockWidget->setMinimumSize(QSize(50, 38));
dockWidget->setWidget(dockWidgetContents);
this->addDockWidget(static_cast<Qt::DockWidgetArea>(1), dockWidget);
//// add tree table widget to dock
treeWidget = new QTreeWidget(dockWidgetContents);
//// creat an object in main window
qGraph = new QGraphicsView(ui.centralWidget);
qGraph->setGeometry(QRect(70, 30, 300, 300));
scene = new QGraphicsScene(qGraph);
scene->setSceneRect(0, 0, 300, 300);
qGraph->setScene(scene);
qGraph->show();
//////// creat push button to resize the dock
QPushButton* btn_Ok = new QPushButton(ui.centralWidget);
btn_Ok->setGeometry(QRect(340, 340, 75, 23));
btn_Ok->setText("Ok");
connect(btn_Ok, SIGNAL(clicked()), this, SLOT(worker_fn()));
}
void QtGuiApplication::worker_fn()
{
QRect rect = dockWidget->geometry();
dockWidget->resize(300, rect.height());
}
I have a very simple window with a QGraphicsView, a QGraphicsScene inside, and a simple QPushButton. When user clicks button, a line should be added to the scene. However, since I set QGraphicsView::NoViewportUpdate, the line shouldn't be displayed. On the opposite, the line gets displayed.
According to the documentation, QGraphicsView will never update its viewport when the scene changes; the user is expected to control all updates. This mode disables all (potentially slow) item visibility testing in QGraphicsView, and is suitable for scenes that either require a fixed frame rate, or where the viewport is otherwise updated externally.
How do I solve this problem?
Here is the code:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QWidget>
#include <QPushButton>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QGraphicsView* view;
QGraphicsScene* scene;
QPushButton* b;
public slots:
void start();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QVBoxLayout>
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
scene = new QGraphicsScene(0, 0, 400, 400);
view = new QGraphicsView(scene);
view->setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
b = new QPushButton("Start");
connect (b, &QPushButton::clicked, this, &MainWindow::start);
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(view);
layout->addWidget(b);
setLayout(layout);
}
MainWindow::~MainWindow()
{
}
void MainWindow::start()
{
scene->addLine(0, 0, 200, 200);
}
I "solved" that. I discovered the viewport doesn't get updated if you do NOT hover (for example) it with the mouse. So, if you do not interact, viewport does not update. However, viewport does not update if you scroll with the mouse wheel inside the qGraphicsView.
I have such program: in my Widget I have qpushbuttons, qslider and qgraphicsview. I place qgraphicsscene in qgraphicsview. The problem is that when I click in QGraphicsscene and want to draw a Point, that was clicked, there is a displacement. When I click in center of QGraphicsScene there is not any problems.
if (mouseEvent->button() == Qt::LeftButton)
{
QPointF pos = mouseEvent->scenePos();
addEllipse(pos.x(), pos.y(), 5, 5, QPen(QColor(Qt::green)), QBrush(QColor(Qt::red)));
}
There is a screen too.
So, the question is how to avoid this moving of scene.
In the screen I have clicked in right bottom, but point was drawn in the center
Try this. In my computer it works without displacement
.*h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QMouseEvent>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
signals:
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
public slots:
};
#endif // GRAPHICSSCENE_H
*.cpp
#include "graphicsscene.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
qDebug() << "in";
if (mouseEvent->button() == Qt::LeftButton)
{
QPointF pos = mouseEvent->scenePos();
addEllipse(pos.x(), pos.y(), 5, 5, QPen(QColor(Qt::green)), QBrush(QColor(Qt::red)));
}
}
Using
GraphicsScene *scene = new GraphicsScene(this);
ui->graphicsView->setSceneRect(50,50,50,50);//for example
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
view->setSceneRect(0, 0, 640, 480);
has helped me