EmmaStone
EmmaStone

Reputation: 23

How to make invisible button on widget with background image?

I want to make a simple application with invisible button.

I set background image for my widget by UI property styleSheet and Resources -
border-image:url(:/image.jpg). I always get something like this

this

and then I try to add button on it

I was trying with

ui->pushButton->setStyleSheet("QPushButton{background: transparent;}");
ui->pushButton->setStyleSheet("background-color: rgba(255, 255, 255, 0);");

and it works with buttons on default background, but not in my case.

Every button that I add takes default parent background image. I dont want to see any hints of a button, but when I click on an area to be able to perform some functionality.

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->centralWidget->setStyleSheet("background-image:url(:image.jpg)");
    ui->pushButton->setStyleSheet("QPushButton{border:none;}");
}

Code an above makes button flat, but it duplicate background image from parent widget anyway.

Have you any idea how to resolve it?

Upvotes: 2

Views: 1889

Answers (2)

Fareanor
Fareanor

Reputation: 6805

I think it's better to answer here than in comments.

You just have to set the following stylesheet for your QPushButton to make it invisible:

QPushButton
{
    border: none;
}

I've made the test and it worked well.

For the tests, I have set the wrapping widget's background-image property. I also did another test with the background-color property instead. It worked in both cases (whether the background is a plain color or a picture/photo).

I hope it helps.


EDIT:

I have written a widget that performs what you want. And I also provided a windows in order to make the below example minimal and complete so that you can reproduce it.

I have tested it and it worked well.

test.h:

#ifndef TEST_H
#define TEST_H

#include <QMainWindow>
#include <QPushButton>

class WidgetWithHiddenButton : public QWidget
{
    Q_OBJECT

    protected:
        QPushButton * invisible_button;

    public:
        WidgetWithHiddenButton(QWidget * parent = nullptr);
        QPushButton * getButton();

    protected:
        void paintEvent(QPaintEvent *) override;
};

class TestWindow final : public QMainWindow
{
    Q_OBJECT

    private:
        WidgetWithHiddenButton * widget;

    public:
        TestWindow();
};

#endif // TEST_H

test.cpp:

#include "test.h"

#include <QApplication>
#include <QStyleOption>
#include <QPainter>
#include <QVBoxLayout>

WidgetWithHiddenButton::WidgetWithHiddenButton(QWidget * parent) : QWidget(parent)
{
    // build your widget as you want.

    invisible_button = new QPushButton("Here is a button", this);
    QVBoxLayout * lay = new QVBoxLayout;
    QHBoxLayout * inner_lay = new QHBoxLayout;
    inner_lay->addStretch();
    inner_lay->addWidget(invisible_button);
    inner_lay->addStretch();
    lay->addLayout(inner_lay);
    this->setLayout(lay);

    this->setStyleSheet("WidgetWithHiddenButton {background-image: url(path_to_image/image.jpg);}");
    invisible_button->setStyleSheet("QPushButton {border: none;}");
}
QPushButton * WidgetWithHiddenButton::getButton()
{
    return invisible_button;
}
void WidgetWithHiddenButton::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

TestWindow::TestWindow()
{
    resize(500, 300);

    widget = new WidgetWithHiddenButton;
    this->setCentralWidget(widget);

    connect(widget->getButton(), &QPushButton::clicked, qApp, &QApplication::quit);
}

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    TestWindow tw;
    tw.show();

    return app.exec();
}

Feel free to adapt it (especially by changing the class name because WidgetWithHiddenButton is very ugly :) ).

Notes:

  • I have written a text in the button in order to make it visible (for tests purposes) but you can remove it if you want the button completely invisible.
  • I connected the QPushButton::clicked() signal to the QApplication::quit() slot in order to perform an action when we click on the area of the button.
  • I redefined the paintEvent() method because it is needed when using Q_OBJECT macro alongside stylesheets over a custom QWidget as the documentation mentioned.
  • Feel free to modify the way I build the widget in the constructor (layouts, sizes, ...) to make it fit your requirements.

Upvotes: 2

scopchanov
scopchanov

Reputation: 8419

Cause

A common misconception is that when a stylesheet without a selector is applied to an element, then it is used only for that element. In fact all element's children are styled as well. Thus a selector should be used to achieve the expected result.

Solution

I would suggest you to change this line in your code

ui->centralWidget->setStyleSheet("background-image:url(:image.jpg)");

to

ui->centralWidget->setStyleSheet(".QWidget { background-image:url(:image.jpg) }");

Important: Note the dot before QWidget. It means style the QWidget, but exclude the subclasses. This is necessary because QPushButton is a subclass of QWidget and otherwise would be affected as well.

Then you can set the pushButton's backgroung color to transparent as you do with

ui->pushButton->setStyleSheet("QPushButton{background: transparent;}");

Example

Here is a simple example I have prepared for you in order to demonstrate the proposed solution (requires cat.png in the resource file under pix/images):

#include <QMainWindow>
#include <QWidget>
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr) :
        QMainWindow(parent) {
        auto *widget = new QWidget(this);
        auto *button = new QPushButton(widget);

        widget->setStyleSheet(".QWidget {"
                              " background-image:url(':/pix/images/cat.png');"
                              " background-repeat: no-repeat;"
                              "}");

        button->setStyleSheet(".QPushButton {"
                              " background-color: transparent"
                              "}");
        button->move(100, 100);
        button->resize(100, 100);

        connect(button, &QPushButton::clicked, [](){
            qDebug("clicked");
        });

        setCentralWidget(widget);
        resize(600, 480);
    }
};

Result

The given example produces a window with a background and a 100x100px invisible clickable area positioned at (100, 100):

Window with a background and an invisible button

Upvotes: 4

Related Questions