QT: shaded window effect (lights out) - c++

I'm opening a modal window from my main window and my interest is to make the background dark so the top window is perfectly visible but the main one looks dark like in the "shade".

You can show some half-transparent widget over the mainwindow and it will create shadow effect.
For example, such widget.
class Overlay : public QWidget
{
public:
Overlay(QWidget *parent) {
setPalette(Qt::transparent);
setAttribute(Qt::WA_TransparentForMouseEvents);
}
protected:
void paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(QBrush(QColor(0,0,0, 150)));
painter.setPen(Qt::NoPen);
painter.drawRect(rect());
}
};
Then create this widget, resize and show:
overlay_.reset(new Overlay(this));
overlay_->resize(size());
overlay_->setVisible(true);
You can play with the shadow color and transperancy by changing brush in paintEvent.
Hope this is the effect you wished.

This is up to the window manager to add such effect.
For example, KWin and Mutter both have their way to handle dialogs. KWin does shade the main window, and I think Mutter does it too with some additional effect.
In Mac OS, modal window are already have special properties to put it in focus on relation of it's patent window.
The way windows handle this is by forcing the focus on the modal I think. But it really is the window manager's job, and up to the user's preference to choose what effect should be active.

Related

Programmatically applying the Qt mouse-hover button highlighting on any button

In a Qt application On Windows, when the mouse cursor hovers over a QPushButton, it will be highlighted with a shimmering outline.
I would like to tell any QPushButton to be highlighted like that, programmatically, without it having the mouse cursor actually hovering it.
Is this possible? I've tried setting focus to the button and played with different stylesheets, but I can't seem to access the mouse-hover outline effect.
Solution
If you want to simulate, that a button is constantly under the mouse, my solution would be to inherit from QPushButton and reimplement the paintEvent method, explicitly setting the state of the button to QStyle::State_MouseOver:
option.state |= QStyle::State_MouseOver;
Note: Please, be aware, that this solution will have different effects on different operating systems, as they use different ways to indicate a hovered button. Under Windows 7 for example the whole button will be highlighted, instead of adding a glowing border.
Background
QPushButton is drawn by QStylePainter, as seen in the source code:
void QPushButton::paintEvent(QPaintEvent *)
{
QStylePainter p(this);
QStyleOptionButton option;
initStyleOption(&option);
p.drawControl(QStyle::CE_PushButton, option);
}
The way the button is drawn is determined by the settings held in QStyleOptionButton, which is a subclass of QStyleOption. QStyleOption in turn has a public state attribute, which holds the state flags that are used when drawing the button. The flag QStyle::State_MouseOver is used to indicate that the button is under the mouse.
Example
Finally, here is an example you could try:
In GlowyButton.cpp:
#include "GlowyButton.h"
#include <QStylePainter>
#include <QStyleOptionButton>
...
void GlowyButton::paintEvent(QPaintEvent * /*event*/)
{
QStylePainter p(this);
QStyleOptionButton option;
initStyleOption(&option);
option.state |= QStyle::State_MouseOver;
p.drawControl(QStyle::CE_PushButton, option);
}
...
The full code of the example could be downloaded from GitHub.

Scrolling in QGraphicsView

I have problem with scrolling in QGraphicsView.
I've set scene rect in my QGraphicsView subclass:
MyQGraphicsView::MyQGraphicsView{
setSceneRect(0,0,2000,2000)
}
And overloaded paintEvent:
void MyQGraphicsView::paintEvent(QPaintEvent *event){
qDebug()<<"Paint event";
QPainter painter(viewport());
painter.setRenderHint(QPainter::Antialiasing);
paint(painter);
}
void MyQGraphicsView::paint(QPainter &painter){
painter.setPen(Qt::NoPen);
painter.fillRect(QRect(0,0,200,200),Qt::gray);
painter.fillRect(QRect(500,500,1000,100),Qt::green);
painter.setPen(QPen(Qt::white,4,Qt::DashLine));
painter.drawLine(QLine(0,35,200,35));
painter.drawLine(QLine(0,165,200,165));
}
When I scroll the second rectangle is not visible. When I resize window it is. Also when scrolling rectangle is extending in wired way.
How should scrolling be implemened in this case? I've found several topics about scrolling in QGraphicsView but none solves my problem.
QGraphicsView inherits QAbstractScrollArea. So its content is displayed in its internal widget that can be obtained using viewport(). If you want to paint something and be able to scroll it, you need to attach an event filter to viewport widget and process its paintEvent, not view's event.
But you should not do this for QGraphicsView. You're trying to do something terribly wrong. You should not reimplement QGraphicsView::paintEvent just to paint something! It totally devalues its advantages. You need to use QGraphicsScene to add something to the view.

How to make popup image? wxWidgets

I'm trying to make a popup image preview window like it's done in Autodesk Revit Architecture:
The behaviour of popup image is:
When the mouse stops for 500 milliseconds over the truncated image, a full-sized popup image appears near the mouse cursor.
The Popup image is not a modal dialog, therefore controls of the main window(wxDialog) are still enabled.
The Popup window disappears on mouse movement.
I tried to do it, but i failed.
First I put wxStaticBitmap on wxDialog and use ShowModal() to show this full-sized image. It works great but as it's Modal, main window becomes disabled.
I tried to make this dialog not modal, but when I try to do it, main window raises(main window is modal) and image disappears.
upd.
Now my code:
class PictureFrame: public wxPopupTransientWindow
{
wxStaticBitmap *m_picture;
public:
PictureFrame( wxWindow *parent );
~PictureFrame();
};
Panel code structure is like this:
class MaterialsPane: public wxPanel
{
PictureFrame* m_popup;
wxTimer* m_timer;
public:
MaterialsPane( wxWindow* parent);
~MaterialsPane();
void OnTimer( wxTimerEvent& event);
void OnMouseMove( wxMouseEvent& event );
....
DECLARE_EVENT_TABLE()
};
Panel is placed in main modal dialog:
class MaterialsFrame: public wxDialog {
MaterialsPane* m_materialsPane;
public:
MaterialsFrame( wxWindow* parent, wxWindowID id = wxID_ANY);
~MaterialsFrame();
};
it helped but not completely. As image appears not under mouse cursor but near it (like in the picture of my question), popup window can't catch mouse movements. I tried to catch mouse movements in main dialog, but it failed, because focus is taken by popup window.
My goal is to close popup after any mouse movement.
You should post your code that 'fails'. It is hard to give specific advice when we have no information of what you are doing.
Have you looked at wxPopupWindow? http://docs.wxwidgets.org/trunk/classwx_popup_window.html
Personally, I find it easier to roll my own. Here's how the one I am working on right now looks
cNewDataPopup::cNewDataPopup( cPatDataset& data )
: wxDialog(NULL,-1,L"New data",wxPoint(200,200),wxSize(570,242),
wxDEFAULT_DIALOG_STYLE|wxSTAY_ON_TOP )
, myData( data )
{
...
Show();
}
To make this popup appear, simply call the constructor.
You would want to pass in your image to be displayed, store it in an attribute, handle the paint event by drawing your image on the client area.

Setting a QDialog to be an alien

In a standalone GUI application where I don't have a windowmanager nor a composite manager I want to display a QDialog to the user to ask for values.
The dialog is quite big, so I want to make it translucent so that the user can look through it to see what happens in the application while the dialog is shown.
The problem is that for translucency of X native windows, there needs to be a composite manager. Qt internal widgets can be painted translucent because they don't correspond to native X windows (aliens) and are completely only known to Qt.
Is there a way to make the background of a QDialog translucent without having a composite manager running? Perhaps making it a normal child widget/alien of the application's main window? Is there a better alternative to this?
I don't know of any way of turning a QDialog into a normal child widget. Looking at the Qt for X11 code, I can't figure out a way of not setting the Qt::WindowFlags passed to the QWidget (parent) constructor so that it would be a plain widget and not a window of its own (but I could be wrong, didn't spend a lot of time on that).
A simple alternative is to use a plain QWidget as your container, instead of a QDialog. Here's a sample "PopupWidget" that paints a half-transparent-red background.
#include <QtGui>
class PopupWidget: public QWidget
{
Q_OBJECT
public:
PopupWidget(QWidget *parent): QWidget(parent)
{
QVBoxLayout *vl = new QVBoxLayout;
QPushButton *pb = new QPushButton("on top!", this);
vl->addWidget(pb);
connect(pb, SIGNAL(clicked()), this, SLOT(hide()));
}
public slots:
void popup() {
setGeometry(0, 0, parentWidget()->width(), parentWidget()->height());
raise();
show();
}
protected:
void paintEvent(QPaintEvent *)
{
QPainter p(this);
QBrush b(QColor(255,0,0,128));
p.fillRect(0, 0, width(), height(), b);
}
};
To show it, call it's popup() slot which will raise it to the top of the widget stack, make it as large as its parent, and show it. This will mask all the widgets behind it (you can't interact with them with the mouse). It hides itself when you click on that button.
Caveats:
this doesn't prevent the user from using Tab to reach the widgets underneath. This could be fixed by toggling the enabled property on your "normal" widget container for example. (But don't disable the PopupWidget's parent: that would disable the popup widget itself.)
this doesn't allow for a blocking call like QDialog::exec
the widgets in that popup won't be transparent, you'd have to create custom transparent-background versions for all the widget types you need AFAIK.
But that's probably less of a hassel than integarting a compositing manager in your environment.

painting inside widget in Qt

I created a very simple GUI that has a push button and a "Graphics View" widget from Display Widgets. On pushing the button I want a line to be drawn across the "Graphics View" widget. I have changed the name of the "Graphics View" widget to gv by right-clicking the widget in design view and then selecting change objectName. I am not able to understand how should the line be drawn. I read various texts on Qt that provided information about QPainter, PaintEvent etc. But I got more confused.
Kindly help me with this. A small sample code shall be really helpful for me as I am new to Qt.
A QGraphicsView is meant for displaying instances of QGraphicsItem that are managed by a component called QGraphicsScene. In your case, you'd create a QGraphicsLineItem and add it to the scene, or directly create it as an item of the scene by calling the addLine member function of your QGraphicsScene instance.
All drawing will be done by Qt itself, assuming that you did connect your graphics view and scene properly. Be sure to read The Graphics View Framework, which gives you an overview over how these components work.
You will find code examples of how to manage and display a scene using the graphics view framework here: http://doc.trolltech.com/4.6/examples-graphicsview.html
You can paint into a QPainter
Either override the paintevent and draw there
void MyDisplayWidget::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.setPen(Qt::green);
p.drawText(10,10,"hello");
}
Or draw into a QImage and display that
QImage image = QImage(size);
QPainter p(&image);
p.drawText(10,10,"hello");
// draw or save QImage
You can even use the same draw function taking a QPainter * to draw either direct to the screen or to an image.
first you must knew some information about QPainter to have benefit of it.
QPainter provides highly optimized functions to do most of the drawing GUI programs require. It can draw everything from simple graphical primitives (represented by the QPoint, QLine, QRect, QRegion and QPolygon classes) to complex shapes like vector paths .and we use it to draw on paint devices
then render it to view,and we have alot of qpaint devices like : QWidget, QImage, QPixmap, QPicture, QPrinter, and QOpenGLPaintDevice you can use any one of them depending on your requirements then create QGraphic scene and add you paint device as qgraphic scene item to be shown in qgraphic view.
here is simple code:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
scene=new QGraphicsScene(this); //allocate your scene to your main widget
view=new QGraphicsView(scene,this);//here is your view
pixmap=new QPixmap(QSize(700,700));// paint device
view->resize(700,700);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *e)
{
painter=new QPainter;// create your painter
painter->begin(pixmap);//add painter to your paint device
painter->fillRect(0,0,300,300,Qt::red);//draw rect
painter->setPen(Qt::yellow);
painter->drawLine(0,0,700,700);//draw line
painter->end();
scene->addPixmap(*pixmap);// add your paint device to your scene
view->show();//then show your view
}