Create a window in qt with shape from an image - c++

Can some one explain me how to make a window in qt according to the shape of some object in an image , for example i have an image of a tree , using that i need to create a window in the shape of a tree ..

After a long search , myself found a good solution , check out this ..
#include <QtGui>
class myMainWindow:public QMainWindow
{
public:
myMainWindow():QMainWindow()
{
setMask((new QPixmap("saturn.png"))->mask());
QPalette* palette = new QPalette();
palette->setBrush(QPalette::Background,QBrush(QPixmap("saturn.png")));
setPalette(*palette);
setWindowFlags(Qt::FramelessWindowHint);
QWidget *centralWidget = new QWidget(this);
QGridLayout *layout = new QGridLayout();
centralWidget->setLayout(layout);
QPushButton* button1 = new QPushButton("Button 1");
button1->setFixedSize(80,50);
layout->addWidget(button1,0,0);
setCentralWidget(centralWidget);
};
~myMainWindow(){};
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
myMainWindow *window = new myMainWindow();
window->resize(600, 316);
window->show();
return app.exec();
}

Here is a recipe for making a widget with a semi-transparent background colour. Just expand from there by making the background fully transparent, then display the tree image on top of that as a background image. Note that the widget will still behave like a rectangular widget in regards to laying out its child elements, so you probably need to deal with this using some custom layout inside the tree shape.

Start from the docs for QWidget::setMask. It has a version which takes a QBitmap and one that takes a QRegion. This is the fundamental function in getting a transparent widget. The toolkit also includes a clock example using the QRegion version -- I suspect a bitmap is just as easy though.

Related

How to fix display problem when I use QGraphicsView and QGraphicsEffect together in Qt?

I have a problem when use QGraphicsView and QGraphicsBlurEffect in my project. When I put them together, my program does not work normally. I wrote a tiny program to reproduce this problem.
The Widget class is inherited from QGraphicsView.
Widget::Widget(QWidget *parent)
: QGraphicsView(parent)
{
scene = new QGraphicsScene(this);
this->setScene(scene);
label = new QLabel;
QPixmap pixmap = QPixmap("../partly_cloudy.png").scaledToWidth(200);
label->setPixmap(pixmap);
label->setGeometry(100,100, pixmap.width(), pixmap.height());
label->setStyleSheet("border:3px;border-color: rgb(255, 100, 0); border-style:solid;");
/* ********image won't show when adding following comment code********
QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
blur->setBlurRadius(10);
label->setGraphicsEffect(blur);
******* */
QGraphicsProxyWidget *proxyWidget = new QGraphicsProxyWidget;
proxyWidget->setWidget(label);
proxyWidget->setPos(10,10);
scene->addItem(proxyWidget);
}
and main.cpp is as follows.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
This is a screenshot when QGraphicsBlurEffect is not used.
However, this is a screenshot when QLabel uses setGraphicsEffect() to bind blur effect.
To solve this problem, I tried to use a QWidget to wrap QLabel. When I did this, QLabel was rendered. However, it seems to be bounded by a rectangle area.
Widget::Widget(QWidget *parent)
: QGraphicsView(parent)
{
scene = new QGraphicsScene(this);
this->setScene(scene);
/* ********/
container = new QWidget;
container->setStyleSheet("border:3px;border-color: blue; border-style:solid;");
/******** */
label = new QLabel(container);
QPixmap pixmap = QPixmap("../partly_cloudy.png").scaledToWidth(200);
label->setPixmap(pixmap);
label->setGeometry(100,100, pixmap.width(), pixmap.height());
label->setStyleSheet("border:3px;border-color: red; border-style:solid;");
QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
blur->setBlurRadius(10);
label->setGraphicsEffect(blur);
QGraphicsProxyWidget *proxyWidget = new QGraphicsProxyWidget;
proxyWidget->setWidget(container);
proxyWidget->setPos(80,80);
qDebug() << proxyWidget->boundingRect();
scene->addItem(proxyWidget);
this->setSceneRect(0,0,640,480);
}
The screenshot of the result is.
I tried to set proxyWidget position to {0,0}, and it works normally. it seems that the position of effect rectangle will not influenced by proxyWidget position.
By the way, the version of Qt is 5.14.2.
I've searched for a long time on net. But no use. Please help or try to give some ideas how to achieve this.

Why QGraphicsView is not shown

I have the following codes in my Qt project with the following main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
The class Widget is a QWidget object with the following constructor:
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_Scene = new QGraphicsScene(this);
QGraphicsLinearLayout* layout = new
QGraphicsLinearLayout(Qt::Orientation::Vertical);
for(int i = 0; i < 10; i++)
{
std::string name = "m_" + std::to_string(i);
GraphicsTextItem* item = new GraphicsTextItem(nullptr, QString(name.c_str()));
layout->addItem(item);
}
QGraphicsWidget* list = new QGraphicsWidget;
list->setPos(0,0);
list->setLayout(layout);
m_Scene->addItem(list);
QGraphicsView* view = new QGraphicsView(this);
view->setScene(m_Scene);
// Why one of these lines must be uncommented?
//m_Scene->setSceneRect(0, 0, 1920, 768);
//QVBoxLayout *ttopLayout = new QVBoxLayout;
//ttopLayout->addWidget(view);
//setLayout(ttopLayout);
}
GraphicsTextItem is just a QGraphicsWidget for displaying text:
class GraphicsTextItem : public QGraphicsWidget
{
public:
QString m_Name;
QColor m_Color;
public:
GraphicsTextItem(QGraphicsItem * parent = nullptr, const QString& name = QString());
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
{
Q_UNUSED(option)
Q_UNUSED(widget)
QFont font("Times", 10);
painter->setFont(font);
painter->setPen(m_Color);
painter->drawText(0, 0, m_Name);
}
};
My question is that why my scene is not shown. I must either define a SceneRect or define a layout on my widget?
I made an even shorter MCVE for demonstration:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QWidget qWinMain;
qWinMain.resize(320, 240);
QFrame qFrm(&qWinMain);
qFrm.setFrameStyle(QFrame::Box | QFrame::Raised);
qFrm.setLineWidth(0);
qFrm.setMidLineWidth(1);
qWinMain.show();
return app.exec();
}
compiled and started in cygwin64. This is how it looks:
There is a main window (with window manager decoration).
There is a child QFrame.
The child QFrame is "pressed" into the upper left corner.
How comes?
What QWidget does ensure: Child widgets are rendered (in front) when QWidget is rendered.
What QWidget is not (directly) responsible for: Layouting child widgets.
For this, a layout manager has to be plugged in:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QWidget qWinMain;
qWinMain.resize(320, 240);
QVBoxLayout qVBox(&qWinMain);
QFrame qFrm(&qWinMain);
qFrm.setFrameStyle(QFrame::Box | QFrame::Raised);
qFrm.setLineWidth(0);
qFrm.setMidLineWidth(1);
qVBox.addWidget(&qFrm);
qWinMain.show();
return app.exec();
}
compiled and started again in cygwin64. This is how it looks:
Now, the QFrame qFrm is filling the QWidget qWinMain nicely. Resize events received in qWinMain will be forwarded to the layout manager qVBox which will re-layout the children of qWinMain (i.e. qFrm) again.
I strongly believe OP's GraphicsView is just not visible because it has no minimal size requirement. (It's just to small to be visible.)
Hence, adding a layout manager ensures that the GraphicsView fills the parent widget client area. Resizing the contents of GraphicsView (by m_Scene->setSceneRect(0, 0, 1920, 768);) is yet another option to fix this, albeit the worse one.
Finally, the link to Qt Doc.: Layout Management.
Layout Management
The Qt layout system provides a simple and powerful way of automatically arranging child widgets within a widget to ensure that they make good use of the available space.
Introduction
Qt includes a set of layout management classes that are used to describe how widgets are laid out in an application's user interface. These layouts automatically position and resize widgets when the amount of space available for them changes, ensuring that they are consistently arranged and that the user interface as a whole remains usable.
All QWidget subclasses can use layouts to manage their children. The QWidget::setLayout() function applies a layout to a widget. When a layout is set on a widget in this way, it takes charge of the following tasks:
Positioning of child widgets
Sensible default sizes for windows
Sensible minimum sizes for windows
Resize handling
Automatic updates when contents change:
Font size, text or other contents of child widgets
Hiding or showing a child widget
Removal of child widgets

QGraphicsBlurEffect resizes Text but not Widget itself

I'm trying to use Qt 5.5.1 QGraphicsBlurEffect in my project, but can't make it work on Mac:
I was trying to make a change by using PerformanceHint, QualityHint or AnimationHint, but didn't succeed. Using QGraphicsColorizeEffect I had the same issue, while QGraphicsOpacityEffect and QGraphicsDropShadowEffect, as well as everything on Linux worked perfectly fine:
How can I change my project file or code to make this graphics issue go away? Is it even possible?
TEMPLATE = app
TARGET = main
QT += widgets
SOURCES += main.cpp
#include <QtWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow window;
QTextEdit *text = new QTextEdit;
text->setReadOnly(true);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(text);
QWidget *widget = new QWidget;
widget->setLayout(layout);
QGraphicsBlurEffect effect;
effect.setBlurRadius(3);
QLabel *test = new QLabel("TEST");
test->setGraphicsEffect(&effect);
(new QHBoxLayout(text))->addWidget(test, 0, Qt::AlignCenter);
window.setCentralWidget(widget);
window.show();
return app.exec();
}
I had a similar problem with QGraphicsOpacityEffect: blurred text and icons when it must be crisp sharp. Seems like a bug in Qt. My solution was to write my own small class containing everything I need with a proper rendering.
Well, you can try to fix Qt... good luck at reading source code of graphics effects. It is quite complicated with all it's dpr and transform matrix and rendering child widgets.

How to draw tiled image with QT

I'm writing interface with C++/Qt in QtCreator's designer. What element to chose to make as a rect with some background image?
And the second question: how to draw tiled image? I have and image with size (1×50) and I want to render it for the parent width. Any ideas?
mTopMenuBg = QPixmap("images/top_menu_bg.png");
mTopMenuBrush = QBrush(mTopMenuBg);
mTopMenuBrush.setStyle(Qt::TexturePattern);
mTopMenuBrush.setTexture(mTopMenuBg);
ui->graphicsView->setBackgroundBrush(mTopMenuBrush);
QBrush: Incorrect use of
TexturePattern
If you just want to show an image you can use QImage. To make a background with the image tiled construct a QBrush with the QImage. Then, if you were using QGraphicsScene for example, you could set the bursh as the background brush.
Here is an example which fills the entire main window with the tiled image "document.png":
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
QGraphicsScene *scene = new QGraphicsScene(100, 100, 100, 100);
QGraphicsView *view = new QGraphicsView(scene);
mainWindow->setCentralWidget(view);
QImage *image = new QImage("document.png");
if(image->isNull()) {
std::cout << "Failed to load the image." <<std::endl;
} else {
QBrush *brush = new QBrush(*image);
view->setBackgroundBrush(*brush);
}
mainWindow->show();
return app.exec();
}
The resulting app:
Alternatively, it seems that you could use style sheets with any widget and change the background-image property on the widget. This has more integration with QtDesigner as you can set the style sheet and image in QtDesigner.

QGraphicsView possible bug?

The example code is from my project. I've tried to make it as short as possible and to the point.
The overlay is used to draw over all the other widgets in the app. This works for most widgets, but today I've started to notice that QAbstractScrollArea subclasses are giving me a hard time. The problem is that the overlay appears not on top, and whatever drawing that happens is blocked.
#include <QtGui/QApplication>
#include <QtGui/QVBoxLayout>
#include <QtGui/QGraphicsView>
#include <QtGui/QPushButton>
class View : public QGraphicsView{
public:
View(){
//delete viewport(); setViewport(new QWidget);
}
};
class Widget : public QWidget{
QWidget* overlay_;
public:
Widget(){
resize(512, 512);
QVBoxLayout* layout = new QVBoxLayout;
QPushButton* button = new QPushButton(" Click Me! ");
layout->addWidget(button);
layout->addWidget(new View);
overlay_ = new QWidget(this);
overlay_->installEventFilter(this);
connect(button, SIGNAL(clicked()),
overlay_, SLOT(show()));
overlay_->hide();
setLayout(layout);
}
bool eventFilter(QObject* target, QEvent* event){
if(target == overlay_){
if(event->type() == QEvent::Paint && overlay_->isVisible()){
overlay_->resize(size());
QPainter painter(overlay_);
painter.setPen(QPen(QColor(1, 102, 192, 255), 1, Qt::SolidLine,
Qt::FlatCap, Qt::MiterJoin));
painter.drawRect(rect().adjusted(60, 0, -60, 0));
return true;
}
}
}
};
int main(int argc, char *argv[]){
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
To fix this in this example and have overlay go on top of View, you'll need to uncomment the commented line at the top. So my question is this: why do I need to delete and assign a new viewport widget in the constructor in order for overlay not get overdrawn?
This isn't a bug with QGraphicsView, it will happen if you use a standard QScrollArea as well.
The issue, I think, is the order in which Qt draws child widgets. Sibling widgets are drawn in the order they are added to the parent (although you can't rely on this).
The reason that resetting the viewport "solved" the problem is because when you do that you create a new QWidget that has no background to be the viewport. The QGraphicsView is still being drawn over the overlay_, it just has a transparent viewport. Notice how it's still drawn behind the pushbutton, however.
If you want to draw an overlay only over the QGraphicsView, you can override QGraphicsView::paintEvent() and do it there. If you want to draw the overlay over your entire widget, I would embed your layout inside a second QWidget and then try using QWidget::raise() to force the overlay visually to the top.