I am subclassing QOpenGLWindow (not QGLWidget or QOpenGLWidget) and calling
auto container = QWidget::createWindowContainer(my_opengl_window);
to place it in the layout of a parent QWidget.
The window displays correctly and I can interact with it, but container (and its parent widget) do not receive context menu events when I right-click within my_opengl_window. I do get a context menu if I right-click on the slim margin between the window and its container.
void MyGLWindow::mousePressEvent (QMouseEvent * e)
{
qDebug (__PRETTY_FUNCTION__);
QOpenGLWindow::mousePressEvent (e);
}
The above shows me that my_opengl_window is receiving mouse clicks. I have also tried e->ignore () but still the parent does not receive a context menu event.
Also, setCursor and setToolTip on the container widget have no effect. I suspect this may be related.
How can I get these mouse events to work on a QOpenGLWindow container?
Related
Just as a QPushButton provides a default clicked() signal, I expected QScrollArea to have a sliderChanged() or similar signal. Interestingly, the QScrollBar does have such a signal.
All I would like to do is to know what part of the huge widget inside the scroll area is visible, whenever the user scrolls it.
There are many solutions, none of which seem elegant to me:
subclass QScrollArea
subclass the widget inside the scroll area, and re-implement its paint event.
create a custom veiwport, using QScrollBar
periodically poll the position of the widget inside the scroll area. This seems to be the worst solution.
Is there a way without subclassing?
There is QAbstractSlider::valueChanged() signal that is emitted when the slider value has changed, with the new slider value as argument. This will notify you as soon as you scroll your view.
WRT the second problem, neither of mentioned points necessary. You need to:
1) Get the position of inner widget (if any) related to the scroll area:
QPoint p = scrollArea->widget()->pos();
It use to be a negative coordinates if you scrolled your view down/right or null without scrolling.
2) Get the size of the visible area
QSize s = scrollArea->viewport()->size();
With these two values you can construct a QRect that will represent the visible area of your inner widget.
I have a QGLWidget that renders an OpenGL scene inside a Qt application. I would like to add some other translucent Qt widgets that are overlaid on top of the QGLWidget. This is more difficult than with standard widgets since the OpenGL drawing context is unknown to Qt's painter classes. So, if I just do the obvious thing and place a transparent toolbar on top of the QGLWidget for instance, the transparent part of the toolbar instead renders black (it doesn't have access to the OpenGL frame buffer when painting).
It seems that the recommended way for handling this sort of thing is to overpaint the 2D content after drawing the OpenGL scene. The linked example seems very straightforward, as long as you're just drawing simple shapes. Instead, what I would like to do is to defer the painting of some child QWidget objects to be done inside the paint event for the QGLWidget.
So, my problem boils down to this:
Prevent the overlay QWidgets from painting in the normal, 2D context.
In the paint event handler for the QGLWidget, paint the overlays after painting the 3D scene that makes up the background.
The second item on this list seems to be simple: I can use QWidget::render() inside the QGLWidget's paint event to draw the desired widgets on top of the viewport. This works just fine.
The first item is more tricky: I need a way to prevent the widgets from painting during the normal course of events and only paint them in the QGLWidget's paint handler. One obvious way to do this is to hide the overlays using QWidget::hide(). This does allow me to paint the widgets atop the OpenGL scene as I would like. However, since the widgets are hidden, they do not respond to mouse or keyboard events. As an example, I'm using a QToolBar with a few buttons on it, and the toolbar is painted properly, but is non-functional (none of the buttons respond to clicks). So, if going down this path, it seems that I would need a way to force the widget to still respond to events even though it is hidden.
Another approach that I've tried is to intercept the QToolBar's paint event using an event filter, with the goal of preventing the toolbar from painting itself. However, the toolbar is still rendered; I'm assuming that this is because the various buttons on the toolbar are child widgets that are still painted, even if I intercept the parent's paint event.
Any ideas on a way that I could accomplish my goal?
I don't understand your issue completely, but I'll try to answer the question stated in the title. You should use event filters. Install an event filter using widget->installEventFilter(object), where widget is a widget you want to block painting, and object is an object of any of your QObject-derived classes. Reimplement eventFilter of this class:
bool MyClass::eventFilter(QObject* object, QEvent* event) {
if (event->type() == QEvent::Paint) { return true; }
return false;
}
When you return true from your eventFilter, the event is filtered and paint doesn't occur.
You can also try to use widget->setUpdatesEnabled(false) to temporarily disable painting. Don't forget to re-enable it when you're done.
I have a class that uses a vertical QSplitter to separate two important widgets (the arrow pointer is at the splitter position):
The upper child widget is a QTextEdit while the lower child is a custom widget that interacts with my app's tagging system. The lower child is collapsed by default; it is only displayed when the user clicks the tag toolbar button or drags the splitter upward. When the button is toggled on, the lower child is displayed, otherwise it remains hidden.
The toolbar button works perfectly but right now I have no way to detect when the user collapses the lower child by dragging the splitter bar all the way down. This causes the toolbar button to stay toggled on when the user collapses the lower child by hand. The inverse is also true; when the user drags the splitter up the button stays off.
I've already tried connecting the QSplitter:splitterMoved(int pos,int index) signal to a slot that un-toggles the button when the lower child (index 1) is collapsed (pos 0) manually but for some reason the signal never gets emitted.
My code (the splitter object is called divide) connects this signal...
connect(divide, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int pos, int index)));
... to this slot:
void Editor::splitterMoved(int pos, int index){
using namespace std;
if((index==1) && (pos==0)){
ui->TagButton->setChecked(false);
}
else{
ui->TagButton->setChecked(true);
}
}
Am I using this incorrectly? The slot currently does nothing no matter what I do to the splitter. Is there a better way to solve this problem?
Are you sure parameter names are allowed in the SLOT macro? A quick test suggests they're not.
Try with:
connect(divide, SIGNAL(splitterMoved(int,int)),
this, SLOT(splitterMoved(int,int)));
UPDATE:
Another point is that pos is not 0 when the child widget #1 is collapsed, on the contrary it reaches its maximum value, since it is the distance from the top. Testing QSplitter:sizes() would be easier.
Example, assuming divide is a class member:
void Editor::splitterMoved(int pos, int index){
if(divide->sizes().at(1)==0) {
ui->TagButton->setChecked(false);
}
else{
ui->TagButton->setChecked(true);
}
In the case of QSplitters you can check a child widget's invisibility using:
QWidget::visibleRegion().isEmpty()
Unlike checking whether the handle is at zero this works for both extremes.
I am having QListWidget, i want to have a Transparent Scrollbar with Image.
Initially that scrollbar should be hidden on scroll only it should show.
How i Can achieve this in Qt ?
Any examples or ideas are welcomed.
How i can apply image to Listview Scrollbar.
Here are the three things you can look at to be able to control the scroll bar for most kinds of widgets in Qt:
VerticalScrollBarPolicy
HorizontalScrollBarPolicy
enum Qt::ScrollBarPolicy.
To be able to track how the user interacts with your QListWidget or any Widget for that matter you need to subclass it and implement the virtual methods from the QWheelEvent and possibly the QKeyEvent.
Scrolling is typically done with the mouse wheel and with the keyboard arrow keys and sometimes page-up and page-down and spacebar. I haven't done a lot with QListWidget, but you should double check which keyboard events/mouse events trigger scrolling.
These events will cause scrolling event even after you set either or both of the ScrollBarPolicies for the widget to be Qt::ScrollBarAlwaysOff.
First you should put in the constructor of your widget
this->setVerticalScrollBar(Qt::ScrollBarAlwaysOff);
this->setHorizontalScrollBar(Qt::ScrollBarAlwaysOff);
So you just need to setMouseTracking(true) for the widget (so that it tracks more than just the clicks) and reimplement at the very least wheelEvent(), and when a wheel event occurs, set the vertical/horizontal scroll bar policies to true and call update on your widget.
If you want to turn the scrollbars back off after a few milliseconds after they have started scrolling, you will need to create a QTimer in your constructor for your subclassed widget and connect it to a slot that sets the scroll bar polices on the timeout. Then you start/restart that timer every time the user does a wheelEvent().
As far as applying an image to the ListView Scrollbar, you should look into subclassing QAbstractScrollBar, if you want to actually put an image on it or change the way it looks. Setting up some tool buttons may also be the way to go if you are trying to put buttons with different icons in place of the scrollbar.
I have an application that will add a Widget to an HBox, which is contained in a ScrolledWindow. When a Widget is added, I would like the parent ScrolledWindow to scroll to the right, where the newly added Widget is. Adding the widget works just fine, my problem is:
How can I make the ScrolledWindow move when a child is added?
My Vala code looks something like:
private void addView() {
var widget = this.createWidget();
this.box.pack_start(widget); // this.box is a HBox
widget.show_all();
var adj = this.parent_win.get_hadjustment(); // parent_win is a ScrolledWindow
adj.set_value(adj.get_upper());
}
The behavior I am getting now is the adjustment will work every other double click (what signals all this). I would like for the adjustment to occur on every double click.
update I have seen this: Gtk, How to scroll at bottom of viewport list? , but there is no real definitive answer given. you mean to tell me i have to set a 1 sec timeout to scroll ?
Use an idle callback instead of a timeout, and use the GtkContainer::add signal to get notified when a new child is added (http://developer.gnome.org/gtk/unstable/GtkContainer.html#GtkContainer-add).