23

There are a few questions on SO about this, all of which seem to say that the only way to remove the dotted border is to set the focusPolicy on widget/item in question to NoFocus. While this works as a temporary fix, this prevents further interaction with said widget/item in the realm of other necessary focusEvents.

Said border in question:

Dotted Focus? Border

Here's an example of why this doesn't work.

  • I have a Non-Modal widget popup, think a lightbox for an image.
  • I want to detect a mousePressEvent outside of the widget and close the widget as a result. To do this, I should catch the focusOutEvent.
  • However, if a vast majority of widgets in my program are set as NoFocus (to remove the border issue), then I cannot catch the focusOutEvent because, you guessed it, they have no focus policy.

Here's another example:

  • I have a QTreeWidget that is subclassed so I can catch keyPressEvents for various reasons.
  • The QTreeWidget is also set as NoFocus to prevent the border. Because of this, however, the widget never has focus and therefore no keyPressEvents can be caught.
  • A workaround for this (kludgy, imo) is to use the widget's grabKeyboard class, which is dangerous if I forget to releaseKeyboard later. This is not optimal.

So then the question is, is there a way to remove this weird (mostly just ugly) dotted border without turning off focus for everything in my app? Thanks in advance!

Community
  • 1
  • 1
Cryptite
  • 1,426
  • 2
  • 28
  • 50

5 Answers5

52

Set outline: 0 of the desired object. Refer following example which sets it for a QTableView.

QTableView
{
    outline: 0;
}

Works for QAbstractItemView inherited classes. (QTreeWidget, QTableWidget etc). Surprisingly this CSS property is not mentioned in the QT Documentation. See QT Style Sheet Reference Documenation.

warunanc
  • 2,221
  • 1
  • 23
  • 40
Desh__
  • 899
  • 1
  • 10
  • 16
  • 6
    Holy god that's all it took. Stick that on your QTreeView style and you're golden. – Cryptite Aug 16 '12 at 22:10
  • 2
    This also works for QAbstractButton inheritet classes, e.g. QPushButton, QRadioButton and QCheckBox. Used it in my C++ Qt Application just now. Great! – Sumyrda - remember Monica Mar 25 '15 at 12:59
  • You sir saved my day, this took my qpushbutton to the next level as my buttons are narrow and the dots were covering text. Small and obvious note for those that don't read between the lines, "outline: 0;" is added directly into your qstylesheet properties. Thanks! – JavaBeast Jan 13 '18 at 04:15
5

On OSX you can do QWidget.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False). Not sure about Win or Linux. You might have to do it through stylesheets.

jdi
  • 90,542
  • 19
  • 167
  • 203
  • Just for sheer fun, I tried setting that, but as you can imagine that did nothing for me in Windows. I've gone ahead and placed a bounty in an attempt to attract more attention to this. Thanks for the help jdi in any case. The app I'm writing will have a Mac port sooner than later, so this'll still be useful. – Cryptite Mar 31 '12 at 17:24
1

Most styles delegate the drawing of the focus indicator to the QStyle::drawPrimitive function with PE_FrameFocusRect as the element to be drawn.

So you should be able to disable that globally with the following style class installed on the application instance:

class NoFocusProxyStyle : public QProxyStyle {
public:

    NoFocusProxyStyle(QStyle *baseStyle = 0) : QProxyStyle(baseStyle) {}

    void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const {
        if(element == QStyle::PE_FrameFocusRect) {
            return;
        }
        QProxyStyle::drawPrimitive(element, option, painter, widget);
    }

};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);    
    a.setStyle(new NoFocusProxyStyle);
    ...

PS: It doesn't work with QGtkStyle for some widgets (buttons, combobox), so it might not work for Windows or Mac either.

alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • I'll have to see if I can't convert that to python for PyQT, but I'll give it a shot. – Cryptite Apr 05 '12 at 14:42
  • @Cryptite: it doesn't work with PyQt (or PySide) because the class `QProxyStyle` isn't exported in python. And since specific styles (`QWindowsStyle`, `QWindowsXPStyle`...) aren't exported either, you can't just override that function in the current style (I tried monkey patching too, to replace drawPrimitive on the `QApplication.style()`, but I'm not really sure if I did it correctly). – alexisdm Apr 07 '12 at 17:39
  • So the plot thickens. There must be some way to achieve this. Somebody in the darkness of the interwebs must've solved this problem. – Cryptite Apr 09 '12 at 13:53
  • I was able to do this with PyQt5. See [my answer](http://stackoverflow.com/a/37659000/1839209). (I would have just left it as a comment but then I can't post an entire code block). – Michael Herrmann Jun 06 '16 at 13:35
1

The dotted border actually annoy me too. I google it many times, try about hundred times to solve it but with less success. Now I want to summary three typical way maybe you already know it, but let's make it more clear so you can understand what you truly need.

First QSS
Qss was claimed as most simply way to solve the problem.
Actually it work quiet well under the non root privilege, but under root it broke.

table.setStyleSheet("QTableView:{outline: 0;}")

non root privilege
non root privilege

root privilege
root privilege

So if your application need a root privilege to run, the QSS maybe doesn't suit your need.

Second it's FrameSheet/FrameShape
It looks will be effective, but it just work well under non root privilege like the above method.

table.setStyleSheet("QTableView:{outline: 0}")
table.setFrameShape(QtWidgets.QFrame.NoFrame)

Third NoFocusDelegate inheritance.
This is a great method, it solve the problem privilege irrelevant

class NoFocusDelegate(QtWidgets.QStyledItemDelegate):
    def paint(self, QPainter, QStyleOptionViewItem, QModelIndex):
        if QStyleOptionViewItem.state & QtWidgets.QStyle.State_HasFocus:
            QStyleOptionViewItem.state = QStyleOptionViewItem.state ^ QtWidgets.QStyle.State_HasFocus
        super().paint(QPainter, QStyleOptionViewItem, QModelIndex)

table.setItemDelegate(NoFocusDelegate())

This method help me to get rid of the dotted border mystery, I hope it will be helpful to you too.

Alopex
  • 131
  • 8
0

You can do this with PyQt5:

class Style(QProxyStyle):
    def drawPrimitive(self, element, option, painter, widget):
        if element == QStyle.PE_FrameFocusRect:
            return
        super().drawPrimitive(element, option, painter, widget)

app.setStyle(Style())
Michael Herrmann
  • 4,832
  • 3
  • 38
  • 53