I have a question about resizing an icon on a QPushButton. Target system is Qt 4.8.6 on Linux. I am using QPushButton to create buttons with icons only, no text. I would like to have the icon as large as possible centered on the button including some margin.
I do not want the button size to adapt to the image size, I want the image size to adapt to the button size, while the button size adapts automaticly to the GUI size through QGridLayout or manually resizing.
When simply creating the button, the icon is only loaded small within the middle:
const QString fileName = "Bitmaps/btn.png";
if( !QFile( fileName ).exists() )
{
qDebug() << "File not found: " << fileName;
}
const QPixmap pixmap = QPixmap( fileName );
m_btn = new QPushButton( QIcon( pixmap ), "", this );
When resizing through manual setting, the icon does not scale:
m_btn->setGeometry( QRect( 100, 100, 50, 50 ) );
To get the icon size rescaled I need to manually call setIconSize(). I can call this within the resize event of the instanciating widget.
But handling the margin still has to be calculated manually.
m_btn->setIconSize( QSize( ( m_btn->size().width() - 12 ),
( m_btn->size().height() - 12 ) ) );
But, as I get from the Qt Documentation there is a Stylesheet based layout thing called "The Box Model" which is applied to QPushButton as well.
http://doc.qt.io/qt-4.8/stylesheet-customizing.html#box-model
So my question is, how do I configure the push button icon to fill the "content" area (marked as grey in the above document).
Possibly how do I configure it, that the icon resizes automaticly?
Your help is appreciated :-)
Related
I am using gstreamer-1.0 and overlaying a video stream on a QVideoWidget in Qt . I want to add transparent label to show on the video . The problem is that when I add the label to the layout , of the widget I render the video on , and keep updating the label continuously it either:
- appears , but its background is the background of the window on which the video is rendered . I mean that the video is no longer rendered in the background of the label. (this is when label is updated faster than video frame rate)
-label doesn't appear and all that I have is the video (if label update rate is less than frame rate )
I tried adding a transparent widget to the video layout and adding the label to the new window but this also failed .
Here is my code
// videoWindow //this is the window on which video is rendered
layTimer=new QGridLayout();
dummyWidget=new QWidget();
timerLabel=new QLabel(dummyWidget);
videoWindow->setLayout(layTimer);
dummyWidget->setAttribute(Qt::WA_TranslucentBackground);
dummyWidget->setStyleSheet("background:transparent;");
timerLabel()->setStyleSheet("background:transparent;");
timerLabel()->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint );
dummyWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint );
timerLabel()->setAttribute(Qt::WA_TranslucentBackground);
layTimer->addWidget(dummyWidget);
How can I solve this ? How can I display only text of the label on the video ?
I made the X button in the LineEdit, when i click on this button, the LineEdit is clear. But with my method, the X button looks a little big and not beautiful, I need to make it smaller. How I can do it?
myLineEdit = new LineEdit;
myLineEdit->setFixedHeight( 25 );
m_clear = m_lineEdit->addAction( QIcon( ":/clearButton" ), QLineEdit::TrailingPosition );
the size of clearButton.png is 12x12 px, so in this case it is enlarged and looks not beautiful like this.
For this solution it is assumed that in the original image the relationship between the foreground size and the background is 1: 1 (this is normal in the icons), so the solution is to increase that relationship, for this we create a new image
QPixmap in(":/clearButton");
QPixmap out(in.size()*10/7);
QRect r= in.rect();
r.moveCenter(out.rect().center());
out.fill(Qt::transparent);
QPainter painter(&out);
painter.drawPixmap(r , in);
painter.end();
QLineEdit *m_lineEdit = new QLineEdit;
m_lineEdit->setFixedHeight(25);
m_lineEdit->addAction(QIcon(out), QLineEdit::TrailingPosition);
Before:
After:
How can I show fixed banner (with some widget like label and button ) in between
QMenuBar and QToolBar ?
Similarly like QStatusBar but in between QMenuBar and QToolBar.
I tried to implement using QToolBar.
// toolbar Banner with lable inside it.
QLabel * bannerLabel = new QLabel(" bannerToobar with label banner.");
bannerLabel->setAlignment( Qt::AlignVCenter );
ui.bannerToobar->addWidget( bannerLabel );
ui.bannerToobar->setAllowedAreas(Qt::ToolBarArea::TopToolBarArea);
ui.bannerToobar->setMovable( false );
QSize banner_sz = ui.bannerToobar->size();
ui.bannerToobar->setFixedHeight( banner_sz.height() * 2 );
QSizePolicy banner_szPolicy( QSizePolicy::Policy::Maximum, QSizePolicy::Policy::Fixed );
banner_szPolicy.setHorizontalStretch(255);
ui.bannerToobar->setSizePolicy( banner_szPolicy );
but i can't prevent user from draging mainToolbar and droping in the same row as my
bannerToolbar
You can force it to wrap initially using QMainWindow::addToolBarBreak, but I don't know a way to prevent it from being put back there later by the user (except for making the toolbars non-moveable).
If there was a QToolbar::dockLocationChanged signal (which seems to have been requsted and resolved in https://bugreports.qt-project.org/browse/QTBUG-1274, but I still don't see the signal anywhere), I suppose you could use insertToolBarBreak to fix it up whenever things have changed. Maybe there's some hackish way you could get notified when the toolbars move.
Or you could use QMainWindow::setMenuWidget to place a widget containing both your QMenuBar and something else into the menu area of the QMainWindow. This could get tricky if you want to support styles (mac/gnome/etc) where the menubar gets lifted out of your window to the top-of-screen and the toolbar gets unified with the window title decorations. But the idea of a banner between menubar and toolbar just naturally has problems in such cases :-)
I want to display an image in my app. I use QtDesigner to design UI, then use pyqt to coding. The problem is the image that will be shown is lager than the widget size on the UI. I refer to offical demo:
QT - Widget Image Viewer Demo
add imagelabel and scrollArea, code as follows:
---- UI init ----
self.label = QtGui.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(40, 140, 361, 511))
self.label.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Preferred)
self.label.setObjectName(_fromUtf8("label"))
self.scrollArea = QtGui.QScrollArea(self.centralwidget)
self.scrollArea.setGeometry(QtCore.QRect(40, 140, 361, 511))
self.scrollArea.setWidget(self.label)
self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
---- function ----
filename = "./Penguins.jpg"
image = QtGui.QImage(filename)
pp = QtGui.QPixmap.fromImage(image)
lbl = QtGui.QLabel(self.label)
lbl.setPixmap(pp)
self.scrollArea.setWidgetResizable(True)
lbl.show()
but it doesn't stretch the image, even no scroll bar appear!
You need to call self.label.setScaledContents(true);. So that QLabel will resize itself to the size of pixmap/image and scroll-bar will get visible. See this documentation.
The default implementation of QLabel::setScaledContents wasn't working for me, since it didn't allow me to keep the aspect ratio when the images where larger then the label's
maximum sizes.
This little helper will scale the image down to fit into a label's maximum size if needed (but not up), always keeping the aspect ratio:
/**
* Fill a QLabel widget with an image file, respecting the widget's maximum sizes,
* while scaling the image down if needed (but not up), and keeping the aspect ratio
* Returns false if image loading failed
****************************************************************************/
static bool SetLabelImage(QLabel *label, QString imageFileName)
{
QPixmap pixmap(imageFileName);
if (pixmap.isNull()) return false;
int w = std::min(pixmap.width(), label->maximumWidth());
int h = std::min(pixmap.height(), label->maximumHeight());
pixmap = pixmap.scaled(QSize(w, h), Qt::KeepAspectRatio, Qt::SmoothTransformation);
label->setPixmap(pixmap);
return true;
}
I do not use PyQt but the QtPixmap control has scaled() functions. You can resize the image before put in the label:
scaled()
scaledToHeight()
scaledToWidth()
This is the sample code I use in C++ to resize an image to the QLabel size:
imatge.load("sprite.png");
QPixmap imatge2 = imatge.scaled(ui->label->width(),ui->label->height());
With some help from you QT sages, I was able to implement this window, with the desired layout and resizeability behavior. Now I have another interesting problem.
I want my entire window to have a "repeat-xy" seamless pattern. If I apply it to a simple window without layout and internal widgets, it works perfectly. I do however, now have a "tree" of widgets within widgets, and I can't set the stylesheet to draw my seamless background image to each and every one, cause it looks unnatural. The image must be underlying to all the widget topology I have. The problem is, it's invisible when i apply it to the bottom all-window-covering widget because it has widgets on top of it.
Is there a solution? maybe "transparent widgets" that can contain visible widgets?
I made the following using only CSS, there's a QPlainTextEdit, two QPushButton and a QLineEdit. In the image i added a red border to the QPlainTextEdit only so it can be seen, the rules are the following
QWidget#Form{
background-image: url(:/img/elephant_pattern.gif);
}
QPlainTextEdit{
background:transparent;
border:1px solid red;
}
As you can see all i had to was setting background transparent in the widgets i wanted.
Write your own widget that inherits QWidget. Reimplement the paintEvent and leave it empty. The widget itself won't be drawn, but its children will be.
my_widget::my_widget( QWidget* parent ) : QWidget( parent )
{
}
void my_widget::paintEvent( QPaintEvent* p_event )
{
// left empty to let my_widget be invisible
}
test_mw::test_mw( QWidget *parent ) : QMainWindow( parent )
{
test_widget = new my_widget( this );
QHBoxLayout* layout = new QHBoxLayout();
QPushButton* button0 = new QPushButton( "Button 0", 0 );
QPushButton* button1 = new QPushButton( "Button 1", 0 );
layout->addWidget( button0 );
layout->addWidget( widget );
test_widget->setLayout( layout );
setCentralWidget( test_widget );
}
Although the paintEvent of my_widget is empty, both QPushButtons are drawn. :-)
There was a QWidget::setBackgroundOrigin() method in earlier versions of Qt.
It's all done with styles now. See the examples http://doc.qt.nokia.com/latest/widgets-styles.html