Qt, how to make Tooltip visible without hovering over the control? - qt

I want tooltips to be visible by default when the container widget gets focus/visible.
I want tooltip to appear without being mouse hover on the respective control.

You need to subclass the widget and override handler(s) for event(s) which should produce tooltip display. In the handler, create a QHelpEvent of type QEvent::ToolTip and enqueue it at the event loop. Finally call the parent's original handler, to let it do what was originally intended.
So specifically for getting focus on button, it would be
class MyButton : public QPushButton {
virtual void focusInEvent(QFocusEvent *) {
if(evt->gotFocus()) {
QPoint pos(0,0);
QHelpEvent* help = new QHelpEvent(
QEvent::ToolTip,pos,this->mapToGlobal(pos));
QCoreApplication::postEvent(this,help);
}
QPushButton::focusInEvent(evt);
}
}
For visibility you would override
void QWidget::showEvent(QShowEvent * event);
and do similar code. You need to adjust relative pos to your taste, because originally tooltip dependens on mouse position which you don't have here. Also keep very tight control over making your widgets focused and/or visible. By default, something gets focus all the time, so you will get tooltips all over the place.

Related

Automatically hiding a Qt QWidget after the user clicks elsewhere

I would like to create a QWidget that acts like a pop-up, and I am having trouble figuring out how to do it.
I want to create a sidebar/drawer that gets shown when the user clicks a button. The user will briefly interact with child widgets of the sidebar. The tricky part is that I want the sidebar to be hidden automatically when the user clicks elsewhere in the application. Worst case I can require the user to manually toggle the sidebar, but automatically hiding it is convenient.
I tried or investigated:
Setting the Qt::Popup window flag, but the sidebar needs to be a widget, not a separate window.
Listening for focus events, but I want to support keyboard navigation. The user should be able to Tab to other widgets while the sidebar remains visible. The sidebar should be hidden when the user actually interacts with the other widgets (such as hitting Enter).
Adding an event filter on the top-level widget, but it doesn't receive events that occur on its children (such as a button being clicked).
Adding an invisible "overlay" widget over the rest of the application, but I want the user to be able to directly click on other widgets. Capturing clicks in the invisible overlay would require the user to click twice (once to clear the overlay, then again to interact with other widgets).
Is this just not feasible?
One possibility might be to install an event filter on the QApplication instance itself. Note, though, that application wide event filters can have a noticeable performance impact so it should only be installed as/when necessary. A mock-up might look something like...
class sidebar: public QWidget {
using super = QWidget;
protected:
virtual bool eventFilter (QObject *obj, QEvent *event) override
{
/*
* Your stuff goes here...
*/
if (auto *widget = dynamic_cast<QWidget *>(obj)) {
if (isAncestorOf(widget)) {
/*
* obj refers to a QWidget of some description that is
* a child of this sidebar instance.
*/
} else {
/*
* widget _isn't_ a child of this sidebar so may need
* to take action (including hiding) depending on the
* specifics of widget and the event details.
*/
}
}
return super::eventFilter(obj, event);
}
virtual void showEvent (QShowEvent *event) override
{
super::showEvent(event);
qApp->installEventFilter(this);
}
virtual void hideEvent (QHideEvent *event) override
{
super::hideEvent(event);
qApp->removeEventFilter(this);
}
};
Will require a certain amount of experimentation obviously :-)

How to hide a QWidget when mouse clicked on out side that widget

I want hide a QWidget when mouse clicks out of that widget just like it have a popup flag:
auto widget = new QWidget(this);
widget->setWindowFlag(Qt::Popup); // this widget will hide, when mouse click out of that widget.
For some reason, I can't set these flags and must implement some thing myself which behaves like this.
Or can I get a mouse event out of that widget?
Solution:
As I said, I can't use Qt flags and have to implement the similar behavior myself.My solution is installEventFilter to QApplication, in the override method eventFilter,I filter the QMouseEvent and send a signal.
Yes, you can get a mouse event out of the widget.
Make a custom widget and reimplement mousePressEvent, which will catch the last click (the ouside-the-widget click that hides the "popup"). But be careful to add the call to QWidget::mousePressEvent(event) in the end, otherwise the last click will be lost and your widget will remain onscreen.
CustomWidget::CutomWidget(QWidget *parent) : QWidget(parent)
{
setWindowFlags(Qt::Popup);
}
void CustomWidget::mousePressEvent(QMouseEvent *event)
{
if (!this->underMouse()) {
//if the click is not on the widget, i.e. if it's the click that hides it,
// you caught it, do what you want to do here.
}
QWidget::mousePressEvent(event);
}
Hope it helps.

How to override all widgit tooltips to have them displayed in a single QTextBrowser widget?

I am new to Qt and therefore do not know all the in's and out's and would therefore like to know how, when you hover your mouse over a checkbox or other field that contains a tooltip, to get that tooltip text and have it applied/displayed in a QTextBrowser widget??
Thanks for any help on this issue.
Each QWidget has a "toolTip" property. To get it you can simply call:
QString toolTip = desiredWidget->toolTip();
Also, as you see, to get a toolTip as a string you don't have to wait until your mouse will hover over the desired widget. After that you can use this toolTip as you want (e.g. display it in QTextBrowser as you wrote in your question).
If you try to dynamically display tooltip of the widget under cursor, try to track mouse movement.
class MyWidget: public SuperclassWidget
{...};
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
const QWidget *widget = childAt(event->pos());
if (widget != NULL)
_textBrowser->setHtml(widget->toolTip());
SuperclassWidget::mouseMoveEvent(event);
}
There may be more clever things to prevent too frequent setting of the same tooltip, e.g. remembering the last widget.

JavaFX tooltip causes MouseOut

Simply put I only show buttons when I am hovered on the AnchorPane. I wanted a tooltip for a button, but when the mouse hovers on the tooltip this causes me to leave the anchorpane and everything disappears.
Any ideas? Using the stage for hovering to show or not doesn't seem to ever cause the buttons to hide.
//this is an AnchorPane
this.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
//Doesn't help: if(!micTooltip.isShowing() && !screenTooltip.isShowing())
showButtons(false);
}
});
similarly the mouse entered shows the buttons. And a tooltip is bound to the buttons.
Try this:
ObservableBooleanValue hover = this.hoverProperty()
.or(micTooltip.getScene().getRoot().hoverProperty())
.or(screenTooltip.getScene().getRoot().hoverProperty());
hover.addListener((obs, wasHovering, isNowHovering) -> showButtons(isNowHovering));
Depending on the exact behavior you need, you might want
hover = this.hoverProperty().or(micTooltip.showingProperty()) ;
etc
You might also find it more convenient to use bindings instead of the listener:
this.getChildren().forEach(button -> button.visibleProperty().bind(hover));
(assuming you want all contents of the anchor pane to appear and disappear on mouseover/out; this line needs to be called after you add the content, obviously).

On Qt widgets like DoubleSpinBox or ComboBox, how do i have custom right click menu

I have a few combo-boxes and double spin boxes on my Qt Dialog. Now I need a "ResetToDefault" item on a menu that comes up when you right click on the widget (spin box or combo box).
How do i get it. Is there some way I can have a custom menu that comes up on right click or Is there a way i can add items to the menu that comes on right click.
First, for Qt4, the simplest way is to create an action to reset the data, and add it the the widget using the addAction method (or use the designer). Then, set the contextMenuPolicy attribute to Qt::ActionsContextMenu. The context menu will appear and the action will be triggered.
Code example:
QAction *reset_act = new QAction("Reset to default");
mywidget->addAction(reset_act);
mywidget->setContextMenuPolicy(Qt::ActionsContextMenu);
// here connect the 'triggered' signal to some slot
For Qt3, you might have to intercept the context menu event, and thus inherit the QSpinBox and others. Or maybe you can intercept the context menu event from the main window, detect if it occurred above the widget supposed to have a context menu (using the QWidget::childAt method) and show it there. But you'll have to test.
For Qt4, you can do this for an editable QComboBox by using your own QLineEdit. Create a derived QLineEdit class which implements the contextMenuEvent
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(QWidget* parent = 0) : QLineEdit(parent){}
void contextMenuEvent(QContextMenuEvent *event)
{
QPointer<QMenu> menu = createStandardContextMenu();
//add your actions here
menu->exec(event->globalPos());
delete menu;
}
};
Then, use the setLineEdit function of QComboBox to set the line edit
MyLineEdit* edit = new MyLineEdit();
comboBox->setLineEdit(edit);
The combo box will now use your line edit class. The createStandardContextMenu function creates the normal context menu and you can add any new actions to it that you like in the contextMenuEvent handler before it is shown.
If the QComboBox is not editable then it doesn't have a default context menu so using the Qt::ActionsContextMenu method is much simpler.
QAbstractSpinBox also has a setLineEdit function so you can use a similar technique. Although, for some reason the setLineEdit function is protected on QAbstractSpinBox but public on QLineEdit.

Resources