How to set image on QPushButton? - qt

I want to set an image on QPushButton, and the size of QPushButton should depend on the size of the image. I am able to do this when using QLabel, but not with QPushButton.
So, if anyone has a solution, then please help me out.

What you can do is use a pixmap as an icon and then put this icon onto the button.
To make sure the size of the button will be correct, you have to reisze the icon according to the pixmap size.
Something like this should work :
QPixmap pixmap("image_path");
QIcon ButtonIcon(pixmap);
button->setIcon(ButtonIcon);
button->setIconSize(pixmap.rect().size());

QPushButton *button = new QPushButton;
button->setIcon(QIcon(":/icons/..."));
button->setIconSize(QSize(65, 65));

You can also use:
button.setStyleSheet("qproperty-icon: url(:/path/to/images.png);");
Note: This is a little hacky. You should use this only as last resort. Icons should be set from C++ code or Qt Designer.

You may also want to set the button size.
QPixmap pixmap("image_path");
QIcon ButtonIcon(pixmap);
button->setIcon(ButtonIcon);
button->setIconSize(pixmap.rect().size());
button->setFixedSize(pixmap.rect().size());

I don't think you can set arbitrarily sized images on any of the existing button classes.
If you want a simple image behaving like a button, you can write your own QAbstractButton-subclass, something like:
class ImageButton : public QAbstractButton {
Q_OBJECT
public:
...
void setPixmap( const QPixmap& pm ) { m_pixmap = pm; update(); }
QSize sizeHint() const { return m_pixmap.size(); }
protected:
void paintEvent( QPaintEvent* e ) {
QPainter p( this );
p.drawPixmap( 0, 0, m_pixmap );
}
};

You can do this in QtDesigner. Just click on your button then go to icon property and then choose your image file.

This is old but it is still useful,
Fully tested with QT5.3.
Be carreful, example concerning the ressources path :
In my case I created a ressources directory named "Ressources" in the source directory project.
The folder "ressources" contain pictures and icons.Then I added a prefix "Images" in Qt So the pixmap path become:
QPixmap pixmap(":/images/Ressources/icone_pdf.png");
JF

Just use this code
QPixmap pixmap("path_to_icon");
QIcon iconBack(pixmap);
Note that:"path_to_icon" is the path of image icon in file .qrc of your project You can find how to add .qrc file here

In case anybody needs a PyQt version of the first answer:
class PictureButton(QAbstractButton):
def __init__(self, picture, parent):
super().__init__(parent)
self.setPicture(QPixmap(picture))
def setPicture(self, picture):
self.picture = picture
self.update()
def sizeHint(self):
return self.picture.size()
def paintEvent(self, e):
painter = QPainter(self)
painter.drawPixmap(0, 0, self.picture)

Related

Where can I find pixmap of Qt MessageBox icons

I am developing my own MessageBox because I need the functionality of:
Do not display this message next time
Which isn't supported by standard message boxes. However I would like to make it look as much as possible as original message box. Therefore I would like to reuse the same icon set you can find when message boxes are displayed.
Is there any way to retrieve this pixmap so that I can use it? Something like:
this->ui->icon->setPixmap(QMessageBox::questionPixmap);
Although this is an old question, I found an easy solution for those seeking an answer to this.
Create a qLabel in your custom class, and then in the constructor of that class create a QIcon with the style you want, convert it into a pixmap and use the QLabel::setPixmap() function to apply it to the one you created:
QIcon icon = style()->standardIcon(QStyle::SP_MessageBoxWarning); //or
//whatever icon you choose
QPixmap pixmap = icon.pixmap(QSize(60, 60));
ui->iconLabel->setPixmap(pixmap);
ui->iconLabel->setScaledContents(true); //you can set this to fill the
//dimensions of your qLabel if you wish.
Try QStyle::standardIcon with QStyle::SP_MessageBoxQuestion.
You can get style from current QWidget or QApplication.
This seems to work:
This is the original source code (internal Qt implementation) that gets the pixmap for message box:
QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb)
{
QStyle *style = mb ? mb->style() : QApplication::style();
int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, mb);
QIcon tmpIcon;
switch (icon) {
case QMessageBox::Information:
tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, 0, mb);
break;
case QMessageBox::Warning:
tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, 0, mb);
break;
case QMessageBox::Critical:
tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, 0, mb);
break;
case QMessageBox::Question:
tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mb);
default:
break;
}
if (!tmpIcon.isNull())
return tmpIcon.pixmap(iconSize, iconSize);
return QPixmap();
}
Creating a similar function provides a way to obtain the pixmap for all these message box styles.
Source: http://www.qtcentre.org/threads/37395-Getting-the-Icon-of-a-MessageBox

Hide QLineEdit blinking cursor

I am working on QT v5.2
I need to hide the blinking cursor (caret) of QLineEdit permanently.
But at the same time, I want the QLineEdit to be editable (so readOnly and/or setting editable false is not an option for me).
I am already changing the Background color of the QLineEdit when it is in focus, so I will know which QLineEdit widget is getting edited.
For my requirement, cursor (the blinking text cursor) display should not be there.
I have tried styleSheets, but I can't get the cursor hidden ( {color:transparent; text-shadow:0px 0px 0px black;} )
Can someone please let me know how can I achieve this?
There is no standard way to do that, but you can use setReadOnly method which hides the cursor. When you call this method it disables processing of keys so you'll need to force it.
Inherit from QLineEdit and reimplement keyPressEvent.
LineEdit::LineEdit(QWidget* parent)
: QLineEdit(parent)
{
setReadOnly(true);
}
void LineEdit::keyPressEvent(QKeyEvent* e)
{
setReadOnly(false);
__super::keyPressEvent(e);
setReadOnly(true);
}
As a workaround you can create a single line QTextEdit and set the width of the cursor to zero by setCursorWidth.
For a single line QTextEdit you should subclass QTextEdit and do the following:
Disable word wrap.
Disable the scroll bars (AlwaysOff).
setTabChangesFocus(true).
Set the sizePolicy to (QSizePolicy::Expanding, QSizePolicy::Fixed)
Reimplement keyPressEvent() to ignore the event when Enter/Return is hit
Reimplement sizeHint to return size depending on the font.
The implementation is :
#include <QTextEdit>
#include <QKeyEvent>
#include <QStyleOption>
#include <QApplication>
class TextEdit : public QTextEdit
{
public:
TextEdit()
{
setTabChangesFocus(true);
setWordWrapMode(QTextOption::NoWrap);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setFixedHeight(sizeHint().height());
}
void keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
event->ignore();
else
QTextEdit::keyPressEvent(event);
}
QSize sizeHint() const
{
QFontMetrics fm(font());
int h = qMax(fm.height(), 14) + 4;
int w = fm.width(QLatin1Char('x')) * 17 + 4;
QStyleOptionFrameV2 opt;
opt.initFrom(this);
return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
expandedTo(QApplication::globalStrut()), this));
}
};
Now you can create an instance of TextEdit and set the cursor width to zero :
textEdit->setCursorWidth(0);
Most straight forward thing I found was stolen from this github repo:
https://github.com/igogo/qt5noblink/blob/master/qt5noblink.cpp
Basically you just want to disable the internal "blink timer" Qt thinks is somehow good UX (hint blinking cursors never were good UX and never will be - maybe try color or highlighting there eh design peeps).
So the code is pretty simple:
from PyQt5 import QtGui
app = QtGui.QApplication.instance()
app.setCursorFlashTime(0)
voilĂ .
Solution in python:
# somelibraries
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.setFocus() # this is what you need!!!
container = QWidget()
container.setLayout(self.layout)
# Set the central widget of the Window.
self.setCentralWidget(container)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
I ran into the same problem but setReadOnly is not a viable option because it alters the UI behavior in other places too.
Somewhere in a Qt-forum I found the following solution that actually solves the problem exactly where it occurs without having impact on other parts.
In the first step you need to derive from QProxyStyle and overwrite the pixelMetric member function:
class CustomLineEditProxyStyle : public QProxyStyle
{
public:
virtual int pixelMetric(PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const
{
if (metric == QStyle::PM_TextCursorWidth)
return 0;
return QProxyStyle::pixelMetric(metric, option, widget);
}
};
The custom function simply handles QStyle::PM_TextCursorWidth and forwards otherwise.
In your custom LineEdit class constructor you can then use the new Style like this:
m_pCustomLineEditStyle = new CustomLineEditProxyStyle();
setStyle(m_pCustomLineEditStyle);
And don't forget to delete it in the destructor since the ownership of the style is not transferred (see documentation). You can, of course, hand the style form outside to your LineEdit instance if you wish.
Don't get complicated:
In QtDesigner ,
1.Go the the lineEdit 's property tab
2.Change focusPolicy to ClickFocus
That's it...

Qt::Pixmap in Qwidget doesn't show up in MainWindow

Here is another newbie to Qt.
What I need to do is to have a scrollable Area in the center of MainWindow, which displays images, and allows user to paint on the image.
Since I cannot add a QPixmap directly to a scrollable Area, I tried to create a subclass of QWidget, like below:
class Canvas: public QWidget
{
public:
Canvas(){
image = new QPixmap(480,320);
image->fill(Qt::red);
}
QPixmap *image;
};
Then I declared Canvas *c in the header file.
In the implementation, I wrote:
canvas = new Canvas;
setCentralWidget(canvas);
However, apparently this does not help to show up the QPixmap. I do not know what to do.
You don't need to subclass QWidget for this. QPixmap is not a widget, so it is not shown anywhere. You need to add your pixmap to some widget, this will work:
in header:
QLabel* imageLabel;
in cpp:
imageLabel = new QLabel(this);
QPixmap image(480,320);
image.fill(Qt::red);
imageLabel->setPixmap(image);
setCentralWidget(imageLabel);

Subclassing QLabel to show native 'Mouse Hover Button indicator'

I have a QLabel with a 'StyledPanel, raised' frame.
It is clickable, by subclassing QLabel;
class InteractiveLabel(QtGui.QLabel):
def __init__(self, parent):
QtGui.QLabel.__init__(self, parent)
def mouseReleaseEvent(self, event):
self.emit(QtCore.SIGNAL('clicked()'))
However, a general opinion is that this 'Box' is not easily recognised as clickable.
In an effort toward usability, I'd like the 'Box' to show it is clickable when the mouse is hovered over it.
Obviously a reaction to a mouse hover is easily achieved by connecting the mouseHoverEvent.
However, the 'button indicator' must be natively inherited, since my Qt application allows the User to change the style (out of Windows XP, Windows 7, plastique, motif, cde).
This image shows the particular widget (bottom right corner) and the mouseHover aesthetics I desire in two different styles.
When a mouse is hovered over 'Box', I'd like it to respond like the combobox has in the top, middle.
(The 'response' is aesthetically native and occurs with all Qt buttons, except in 'CDE' and 'motif'styles.).
Is there a way to implement this with PyQt4?
(I suppose non-native solutions would involve QGradient and checking the native style, but that's yucky.)
UPDATE:
lol4t0's idea of a QLabel over a QPushButton.
Here's my pythonic implementation with signals working properly and all the appropriate button aesthetics.
The RichTextBox is the widget you would embed into the program.
from PyQt4 import QtCore, QtGui
class RichTextButton(QtGui.QPushButton):
def __init__(self, parent=None):
QtGui.QPushButton.__init__(self, parent)
self.UnitText = QtGui.QLabel(self)
self.UnitText.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
self.UnitText.setAlignment(QtCore.Qt.AlignCenter)
self.UnitText.setMouseTracking(False)
self.setLayout(QtGui.QVBoxLayout())
self.layout().setMargin(0)
self.layout().addWidget(self.UnitText)
Thanks!
Specs:
- python 2.7.2
- Windows 7
- PyQt4
Main idea
You can add QLabelabove QPushButton (make QLabel child of QPushButton) and show rich text in label, while clicks and decorations can be processed with QPushButton
Experiment
Well, I am a C++ programmer, but there is nothing complicated, I hope, you understand the code
Implementing main idea:
QLabel * label = new QLabel(pushButton);
label->setText("<strong>sss</strong>");
label->setAlignment(Qt::AlignCenter);
label->setMouseTracking(false);
pushButton->setLayout(new QVBoxLayout(pushButton));
pushButton->layout()->setMargin(0);
pushButton->layout()->addWidget(label);
And this almost works! The only one silly bug (or my global misunderstanding) is that when you press button with mouse and then release it, it remains pressed.
- So, it seems we need to reimplement mouseReleaseEvent in our label to fix always pressed issue:
I'm pretty sure, there is a bit more elegant solution, but I'm too lazy to find it now, so, I made following:
class TransperentLabel: public QLabel
{
public:
TransperentLabel(QWidget* parent):QLabel(parent) {}
protected:
void mouseReleaseEvent(QMouseEvent *ev)
{
/*
QApplication::sendEvent(parent(), ev); -- does not help :(
*/
static_cast<QPushButton*>(parent())->setDown(false);
static_cast<QPushButton*>(parent())->click(); //fixing click signal issues
}
};
As #Roku said, to fix that issue, we have to add
label->setTextInteractionFlags(Qt::NoTextInteraction);
#Lol4t0, i have some improvements for your method...
This is my header file:
#ifndef QLABELEDPUSHBUTTON_H
#define QLABELEDPUSHBUTTON_H
#include <QPushButton>
class QLabel;
class QLabeledPushButton : public QPushButton
{
Q_OBJECT
QLabel * m_label;
public:
QLabeledPushButton(QWidget * parent = 0);
QString text() const;
void setText(const QString & text);
protected:
void resizeEvent(QResizeEvent * event);
};
#endif // QLABELEDPUSHBUTTON_H
And there is my cpp file:
#include <QLabel>
#include <QVBoxLayout>
#include <QResizeEvent>
#include "QLabeledPushButton.h"
QLabeledPushButton::QLabeledPushButton(QWidget * parent)
: QPushButton(parent)
, m_label(new QLabel(this))
{
m_label->setWordWrap(true);
m_label->setMouseTracking(false);
m_label->setAlignment(Qt::AlignCenter);
m_label->setTextInteractionFlags(Qt::NoTextInteraction);
m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
}
QString QLabeledPushButton::text() const
{
return m_label->text();
}
void QLabeledPushButton::setText(const QString & text)
{
m_label->setText(text);
}
void QLabeledPushButton::resizeEvent(QResizeEvent * event)
{
if (width()-8 < m_label->sizeHint().width())
setMinimumWidth(event->oldSize().width());
if (height()-8 < m_label->sizeHint().height())
setMinimumHeight(event->oldSize().height());
m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
}
So text on QLabel is always visible. QPushButton can't be too small to hide part of text. I think this way is more comfortable to use...

Animating image replacement in Qt

I'm trying to animate the change of a QPixmap, inside QLabel.
I have MainWindow which holds several objects that derive from QScrollArea. Each of these holds a QLabel member.
Using mousePressEvent() I am able to replace the picture of each QLabel using setPixmap(). However, that simply switches the image in each QLabel, while what I would like to achieve is an animation where a new image slides over the existing one.
First I tried using a QTimeLine to draw the QPixmap on the QLabel myself (I've created a class that derives from QLabel for that, and wrote my own setPixmap()) but that didn't work. Next I tried using QPropertyAnimation but it can't construct on a Pixmap without me implementing a sub class for that as well.
Any thoughts or ideas are appreciated.
You will need a QObject with a property that can be animated, and generates the intermediate frames for the animation. An incomplete example:
class LabelAnimator : public QObject
{
Q_OBJECT
Q_PROPERTY(float progress READ progress WRITE setProgress)
public:
LabelAnimator(QLabel* label) : mProgress(0.0f),
mLabel(label),
mAnimation(new QPropertyAnimation(this, "progress", this)
{
mAnimation->setStartValue(0.0f);
mAnimation->setEndValue(1.0f);
}
void setProgress(float progress) {
mProgress = progress;
QPixmap pix = mOriginalPixmap;
int offset = - mLabel->width() * (1.0f-progress);
QPainter painter(&pix);
painter.paint(off, 0, mNewPixmap);
painter.end();
mLabel->setPixmap(pix);
}
void setPixmap(const QPixmap& pix) {
mOriginalPixmap = mLabel->pixmap();
mNewPixmap = pix;
mAnimation->start();
}
};
QLabel was never designed for such uses. Draw your QPixmaps inside a QGraphicsView, it is far more focused towards rendering effects and animations.

Resources