Qt Popup as a completer window - qt

I need to make some kind of popup window that contains propositions to complete sentences in text editor (QTextPlainEdit). This window needs to be on top of all windows of this application. Also this popup mustn't interrupt typing in the text editor when it appears. I tried different types of flags for QWidget that implements this completer but all I have got is that this completer window is placed above all windows of OS (even if this application is not active) or it interrupts typing in the text editor and makes main window not active any time it appears.
What flags should I use for completer widget?

You could try to use QWidget::setWindowFlags(Qt::Window | Qt::FramelessWindowHint).
Otherwise you could use a customized version of Qt::Popup, by overriding the automatic closing behavior.
You could also try this: if you set the QTextPlainEdit's parent as the completer's parent it should do what you want, provided that the parent does not have a layout (otherwise it will not "float").

The Qt docs contain an example that implements a google-based auto-completer widget, here: http://qt-project.org/doc/qt-4.8/network-googlesuggest.html.
As far as I can tell, they do two things that might be relevant to your situation. One is the flags they set on the popup widget:
popup = new QTreeWidget;
popup->setWindowFlags(Qt::Popup);
popup->setFocusPolicy(Qt::NoFocus);
popup->setFocusProxy(parent);
The other is a custom event filter on the popup widget, which forwards most keypress-events to the editor widget, and closes the auto-completer on Enter or Escape.

Related

Is there a way to show tooltip on disabled QWidget

I have a Qt form, where I have a button and menu. For various reasons I can disable certain elements, e.g button or some actions in the menu.
Is there a way I could show a tooltip or when the mouse is hovered over the disabled button or menu item with an explanation as to why it is disabled?
I am using Qt 4.8.
Thanks!
You can set the tooltip dynamically based on the state of the QWidget or by simply toggling both at the same time. Upon disabling/enabling the widget from somewhere just call QWidget::setToolTip(...) with the QString you want the tooltip to display when hovering with the mouse over the given widget. For example if you have a public slot called toggleButton(bool toggleFlag) which toggles the enable-setting of a button you can do:
void MyWidget::toggleButton(bool toggleFlag) {
this->ui->myButton->setEnabled(toggleFlag);
this->ui->myButton->setToolTip(toggleFlag ? QString("Enabled wohoo!") : QString("Disabled because I like it"));
}
You can of course do also change the tooltip by calling QWidget::isEnabled() and act upon its return value. Since you haven't given any code I can only assume how you toggle your button(s) so that's all I can give you for now.
UPDATE: It was pointed in the comments that tooltips don't work with disabled widgets due not receiving mouse events. Both statements are not true (note that I have used the same tooltip message since due to lack of minimal working example I didn't want to write a whole new project from scratch and used an existing one of mine instead):
Hovering a disabled button triggers the tooltip
Hovering an enabled button triggers the tooltip

QCompleter popup position

I'm having trouble trying to move the QCompleter popup view position.
I tried the QCompeter:complete and it's pops the completer view in the position as I wanted.
But if I start typing it close it, and open the completer in the 'default' position.
I also tried the QCompleter:setPopup() function.
I create a QListView and I tried to moved to different position.
And still the QCompleter popup view remains in the same position.
In my project I'm using a QFrame that wrap QLineEdit.
And I want that the completer view will get the QFrame position.
I succeed to set the completer view width via setFixedWidth() function.
but not to move the position.
Any suggestions ?
Thanks.
I suggest setting the CompletionMode to InlineCompletion, so there will be no popup. Then make your QListView indepedant of the QLineEdit; just react to signals that indicate when a view types some text, leaves the QLineEdit, etc (hint: subclass QListView) and sets the text in QLineEdit when a user selects a value from the list.
I think it will be difficult to override the placement since QCompleter takes ownership of your QListView. (Personally I think it does not make much sense to place the completion list somewhere else than next to the input field, but alas...)

Detecting click outside QWidget

My application has non-rectangular popup widgets.
their class defines the following to achieve that transparency:
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
I also use:
this->setWindowFlags(Qt::Popup| Qt::FramelessWindowHint);
The problem is that on windows 7, an automatic "shadow" is being drawn on the bottom and right sides of my window. This is highly undesirable.
So, I tried using Qt::Tool instead of Qt::Popup
this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
This works visually. No shadow, but now a mouse click outside my widget window will not automatically close/hide it as it would have done with a Qt::Popup.
So, I need one of these two solutions:
A way to have Qt::Popup and get rid of that automatic windows shadow decoration
A way to let the Qt::Tool window a mouse click occurred outside of it.
One note: My application is built for Windows XP and up. I cannot use a Vista/Win7 only runtime DLLs, nor can i have a "Windows XP" and "Vista and up" separate builds.
Any advice will be welcome.
You could manually watch for when the focus changes from your Qt::Tool window. So basically you watch for when the focus goes onto another window of your process or when your application loses focus.
How to detect that my application lost focus in Qt?
Hope that helps.
Finally after realizing that no amount of "SetFocusPolicy" calls will allow me to receive those events for a Qt::Tool window, I've resorted to something else to fix my problem:
I kept the Qt:tool as Qt::Popup caused an undesired shadowing effect, tarnishing my owner draw frame. Removing this style cannot be done in Qt and I didn't want to mess with platform specific conditional code.
I installed an event filter with my Qt::tool window and I began receiving events that assisted me in understanding when other parts of my application were clicked, or if the application itself lost focus to another application. This was what I needed, functionality wise. I could also get an event when users click the non-client areas of the application's main window, such as the windows caption so that I can close it when dragging begins etc.
My solution for Windows 7:
QDialog *d = new QDialog;
d->setStyleSheet("background:transparent;");
d->setAttribute(Qt::WA_DeleteOnClose, true);
d->setAttribute(Qt::WA_TranslucentBackground, true);
#ifdef Q_OS_WIN
d->createWinId();
#endif
d->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
d->show();
I set my QListView
d->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
Install eventfilter and used MousePressEvent to hide qlistview widget.
MousePressEvent on list never comes to filter they produce other events which I didn't debug.
So if you want to design auto completer this will be perfect. Tested in Qt5.3.1.

How to open "external link" by clicking a menu item?

I need to open some link (in my default browser) in a way similar to setOpenExternalLink on Qlabel, but by clicking on an item in the menu.
Is there some simple way?
I think about using Qlabel with required link and use some action/event to pretend the click on it, meanwile the Qlabel was hidden.
Upon clicking the specific menu item (handled using your standard signals and slots) you could use openUrl(const QUrl &url) of QDesktopServices to have that link launch in your default browser.
As the documentation states, it will open
...the given url in the appropriate Web browser for the user's desktop environment, and returns true if successful; otherwise returns false.
So no need for fancy tricks with QLabels and the like.

How to remove focus from a QLineEdit when anyplace else on the window is clicked

I'm working on a custom Qt button that allows you to edit the text on the button if you double click it. When the button is double clicked, a QLineEdit appears where the text on the button is allowing the user to edit the text on the button. My requirement is that if the user clicks anywhere in the application window, the QLineEdit should disappear and cancel the edit operation. This works in some cases. Specifically, it works if I click on anything that is capable of text entry. Other portions of the window don't work as expected. I'll click on a blank portion of the application window, and the QLineEdit retains its focus. How can I remove its focus in these cases?
I've found a solution that seems to work, though I'm still open to other options if there are any. I'm using PyQt4, so my example is in python:
Create a subclass of QLineEdit just so I have a new type. I don't want or need this behavior on all QLineEdit instances; just these specific ones.
class MyLineEdit(QtGui.QLineEdit):
pass
Now, in my QMainWindow subclass, I override the mousePressEvent() implementation. It gets the currently focused widget. If that widget is of type MyLineEdit, clear the focus.
class MyMainWindow(QtGui.QMainWindow):
def ...
def mousePressEvent(self, event):
focused_widget = QtGui.QApplication.focusWidget()
if isinstance(focused_widget, MyLineEdit):
focused_widget.clearFocus()
QtGui.QMainWindow.mousePressEvent(self, event)
def ...
This gets me the behavior I'm looking for so that if the user clicks anywhere on the application's window, the focus is cleared.
Edit: I did find one caveat to this. I have a QTreeView in the main window. If the user clicks on the tree view, focus is not removed from the text edit field.
Catch the clicked() signal of your parent widget and call yourLabel->clearFocus() (that unfortunatelly happens to not be a slot, making things more complicated) there.
I followed Grant Limberg instruction here but figured out that, in my case, a simple:
QApplication.focusWidget().clearFocus()
would fix the problem.
I'm not sure if this also works in Qt4 (I'm using PyQt5) but you can change the FocusPolicy of the QMainWindow or parent widget to clear the focus in the QLineEdit. As per https://doc.qt.io/qt-5/qwidget.html#focusPolicy-prop
I've changed the policy of my QMainWindow to Qt.StrongFocus and it worked like the functionality described in the question.
If done in C++ I would do something along the lines of:
connect(myWidgets->MyLineEdit, SIGNAL(returnPressed()), this, SLOT(onLineEditDone());
void onLineEditDone()
{
myWidgets->MyLineEdit->clearFocus();
}
For this particular case I would use editingFinished() instead of returnPressed(), probably, but I would NOT use textChanged(QString).

Resources