0

I've made a program with pyQT5 on Windows which works great, but now I'm switching back to Linux and the program is buggy, when I move the window with the custom titlebar sometimes it jumps across the screen

I used this post to write the code: Custom Titlebar with frame in PyQt5

Anyone can help me

Here is a simplified sample code:

import sys
from PyQt5.QtCore import QPoint
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QHBoxLayout, QLabel
from PyQt5.QtWidgets import QPushButton, QVBoxLayout, QWidget


class MainWindow(QWidget):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.layout = QVBoxLayout()
        self.layout.addWidget(MyBar(self))
        self.setLayout(self.layout)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.addStretch(-1)
        self.setMinimumSize(800, 400)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.pressing = False


class MyBar(QWidget):

    def __init__(self, parent):
        super(MyBar, self).__init__()
        self.parent = parent
        print(self.parent.width())
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.title = QLabel("My Own Bar")

        btn_size = 35

        self.btn_close = QPushButton("x")
        self.btn_close.clicked.connect(self.btn_close_clicked)
        self.btn_close.setFixedSize(btn_size, btn_size)
        self.btn_close.setStyleSheet("background-color: red;")

        self.btn_min = QPushButton("-")
        self.btn_min.clicked.connect(self.btn_min_clicked)
        self.btn_min.setFixedSize(btn_size, btn_size)
        self.btn_min.setStyleSheet("background-color: gray;")

        self.btn_max = QPushButton("+")
        self.btn_max.clicked.connect(self.btn_max_clicked)
        self.btn_max.setFixedSize(btn_size, btn_size)
        self.btn_max.setStyleSheet("background-color: gray;")

        self.title.setFixedHeight(35)
        self.title.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(self.title)
        self.layout.addWidget(self.btn_min)
        self.layout.addWidget(self.btn_max)
        self.layout.addWidget(self.btn_close)

        self.title.setStyleSheet("""
            background-color: black;
            color: white;
        """)
        self.setLayout(self.layout)

        self.start = QPoint(0, 0)
        self.pressing = False

    def resizeEvent(self, QResizeEvent):
        super(MyBar, self).resizeEvent(QResizeEvent)
        self.title.setFixedWidth(self.parent.width())

    def mousePressEvent(self, event):
        self.start = self.mapToGlobal(event.pos())
        self.pressing = True

    def mouseMoveEvent(self, event):
        if self.pressing:
            self.end = self.mapToGlobal(event.pos())
            self.movement = self.end-self.start
            self.parent.setGeometry(self.mapToGlobal(self.movement).x(),
                                    self.mapToGlobal(self.movement).y(),
                                    self.parent.width(),
                                    self.parent.height())
            self.start = self.end

    def mouseReleaseEvent(self, QMouseEvent):
        self.pressing = False

    def btn_close_clicked(self):
        self.parent.close()

    def btn_max_clicked(self):
        self.parent.showMaximized()

    def btn_min_clicked(self):
        self.parent.showMinimized()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

I have no idea where the problem is, and I didn't test it under macOS

  • I cannot reproduce it on fluxbox, so it *could* be related to the window manager. Can you provide a video of the problem using a screen recorder? Can you also try to restrict to the specific movements that cause the problem? Btw, that function is unnecessarily complex and partially wrong: 1. there's no need for `setGeometry()`: `move()` is fine enough; 2. using global coordinates is also unnecessary; 3. the parent could *not* be the window. Just use `self.start = event.pos()` in `mousePressEvent` and `self.window().move(self.window().pos() + (event.pos() - self.start))` in `mouseMoveEvent`. – musicamante Jan 26 '22 at 13:39
  • Actually i use KDE Plasma, i will try to make a video, thanks for your answer, i'll will experiment with this. My first attent was with TKinter and i made it by myself, so it was simpler like you explain but i didn't managed to reproduce the methods with pyqt5. – sebastien deepwali Jan 26 '22 at 14:29
  • It *is* simpler, if done properly. In the answer you linked, the `move()` way wasn't valid because their approach was unnecessarily complex to begin with, and it's probably the cause of your issue. Try to do what described in my previous comment (just use those simple lines, don't use the existing code), and it should work as expected. – musicamante Jan 26 '22 at 14:38
  • I don't understand since i restarted my computer, the problem don't exist anymore ... Sure it must be related to the WM, when you say you cannot reproduce, this mean there is no problems or it doesn't work at all ? – sebastien deepwali Jan 26 '22 at 14:40
  • I don't reproduce the problem, it works as expected. But I still strongly suggest you to avoid `setGeometry()` and use what described above: it's safer, more correct and much simpler. – musicamante Jan 26 '22 at 14:45
  • No problem, The problem persist you can look at : https://1drv.ms/v/s!AuZNp5hM3_qtgYQFq-WAwCtU4PCOwQ?e=HTUAgI – sebastien deepwali Jan 26 '22 at 15:00
  • Have you tried what written above? – musicamante Jan 26 '22 at 15:02
  • No i will do this later today, now i have something to do – sebastien deepwali Jan 26 '22 at 15:23
  • ok i tried, works perfectly, much simpler like i've done before with Tk, thanks a lot – sebastien deepwali Jan 26 '22 at 15:42
  • It work for sometime but after the problem appear with the solution – sebastien deepwali Jan 28 '22 at 03:02
  • I suggest you to look at [my new answer](https://stackoverflow.com/a/70869383/2001654) to that post and eventually comment there. – musicamante Jan 28 '22 at 03:08
  • The problem of moving is better handle with your solution, but my second monitor interact with the other and seem to result in a bug sometimes too. And when i switch between the master and the slave it keep outside an imaginary taskbar (of 30 pixels) – sebastien deepwali Jan 28 '22 at 18:35
  • What "keeps outside"? Do you have different DPI/scaling settings in your screens? – musicamante Jan 28 '22 at 18:46
  • once i put the window in the main screen the window manager prevent the window to pass on top of the taskbar, when i change the window to the second screen (without taskbar on top) the WM keep the same restriction of 30 pixel on top of the screen) And sometimes the window jump quickly between 2 positions – sebastien deepwali Jan 28 '22 at 20:03
  • What OS and window manager are you using? – musicamante Jan 28 '22 at 20:09
  • I'm using KDE Plasma under Ubuntu Studio 21.10 . My first monitor is an external 1920x1080 monitor and the second the built-in monitor of my laptop under 1600x900 – sebastien deepwali Jan 28 '22 at 20:27
  • 1
    Try changing to `self.window().move(event.globalPos() - self.clickPos)` – musicamante Jan 30 '22 at 21:09
  • Now that's ok, thank you very much for your help. I saw you write a sampler manager, do it worth the time to install it ? How can i send you a message ? – sebastien deepwali Feb 05 '22 at 00:34
  • You're welcome. And sorry, that was my bad: I completely forgotten that some window managers do restrict the window position, thus causing inconsistent behavior of the local position. I updated my proposed answer in the other post, I suggest you to test it again; if you still find any strange behavior please comment there, but if it works you can obviously upvote it ;-) – musicamante Feb 05 '22 at 01:28
  • How to do this *what*? – musicamante Feb 05 '22 at 02:09
  • vote your comment, i found sorry – sebastien deepwali Feb 05 '22 at 02:11
  • I was referring to the new answer I added to the post you linked in your question, not my comment. Go there and look for it. To upvote a question or answer click on the ^ arrow on its left (you need at least 15 reputation points, which you already got). If you don't remember how the site works, please carefully review the [tour] again. – musicamante Feb 05 '22 at 02:15

0 Answers0