Reputation: 4044
I found an example to set borders on a frameless window, however it's not draggable. How can I make a frameless window draggable? Especially if I can see an example it'll be awesome. Here is my example code(normally the code is longer, that's why there are much libraries just don't mind them);
from PyQt5.QtWidgets import (QMessageBox,QApplication, QWidget, QToolTip, QPushButton,
QDesktopWidget, QMainWindow, QAction, qApp, QToolBar, QVBoxLayout,
QComboBox,QLabel,QLineEdit,QGridLayout,QMenuBar,QMenu,QStatusBar,
QTextEdit,QDialog,QFrame,QProgressBar
)
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QIcon,QFont,QPixmap,QPalette
from PyQt5.QtCore import QCoreApplication, Qt,QBasicTimer
import sys
class cssden(QMainWindow):
def __init__(self):
super().__init__()
self.mwidget = QMainWindow(self)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
#size
self.setFixedSize(320, 450)
self.center
#label
self.lbl = QLabel(self)
self.lbl.setText("test")
self.lbl.setStyleSheet("background-color: rgb(0,0,0);"
"border: 1px solid red;"
"color: rgb(255,255,255);"
"font: bold italic 20pt 'Times New Roman';")
self.lbl.setGeometry(5,5,60,40)
self.show()
#center
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
app = QApplication(sys.argv)
app.setStyleSheet("QMainWindow{background-color: darkgray;border: 1px solid black}")
ex = cssden()
sys.exit(app.exec_())
Upvotes: 14
Views: 21833
Reputation: 119
I released a pyqt frameless window repo on GitHub, which is implemented by pywin32
on Windows, xcffib
on Linux and pyobjc
on macOS.
Here is the repo link: https://github.com/zhiyiYo/PyQt-Frameless-Window
Upvotes: 4
Reputation: 21
You can use the startSystemResize, startSystemMove functions of QWindow since Qt 5.15, which make things a lot more easier.
Here's the example of how to use it:
def mousePressEvent(self, e):
if e.button() == Qt.LeftButton:
if self._resizing:
self._resize()
else:
if self._pressToMove:
self._move()
return super().mousePressEvent(e)
def _move(self):
window = self.window().windowHandle()
window.startSystemMove()
def _resize(self):
window = self.window().windowHandle()
window.startSystemResize(Qt.LeftEdge) // or the other ones
I use both functions to my frameless window below and it works perfectly.
You can check it out to my repo if you want: https://github.com/yjg30737/pyqt-frameless-window
Upvotes: 1
Reputation: 1
class Window(QWidget):
def __init__(self):
super().__init__()
self.center()
self.oldPos = = self.pos()
self.isMoveApp = False
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
pos = qr.topLeft()
self.topLabelPos = [pos.x(), pos.y(), pos.x()+720, pos.y()+60]
def mousePressEvent(self, event):
self.isMoveApp = False
self.oldPos = event.globalPos()
x, y = self.oldPos.x(), self.oldPos.y()
if x > self.topLabelPos[0] and x < self.topLabelPos[2]:
if y > self.topLabelPos[1] and y < self.topLabelPos[3]:
self.isMoveApp = True
def mouseMoveEvent(self, event):
if self.isMoveApp:
delta = QPoint(event.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
x, y = self.topLabelPos[0] + \
delta.x(), self.topLabelPos[1] + delta.y()
self.topLabelPos = [x, y, x+720, y+60]
Header label x = 0 y = 0 width = 720 height = 60 #click header label to move app
Upvotes: 0
Reputation: 81
Adding to Elad Joseph's answer, the following events need to be updated for PyQt6:
def mousePressEvent(self, event):
self.oldPos = event.globalPosition().toPoint()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPosition().toPoint() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPosition().toPoint()
Upvotes: 1
Reputation: 604
here is dragable and resizable frameless window
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class movable_label(QLabel):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.setStyleSheet("background-color: #ccc")
self.setMinimumHeight(30)
def mousePressEvent(self, e):
if e.button() == Qt.LeftButton:
if self.parent.press_control == 0:
self.pos = e.pos()
self.main_pos = self.parent.pos()
super().mousePressEvent(e)
def mouseMoveEvent(self, e):
if self.parent.cursor().shape() == Qt.ArrowCursor:
self.last_pos = e.pos() - self.pos
self.main_pos += self.last_pos
self.parent.move(self.main_pos)
super(movable_label, self).mouseMoveEvent(e)
class main(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(Qt.FramelessWindowHint)
self.central = QWidget()
self.vbox = QVBoxLayout(self.central)
self.vbox.addWidget(movable_label(self))
self.vbox.addWidget(QPushButton("Click"))
self.vbox.setAlignment(Qt.AlignTop)
self.vbox.setSpacing(0)
self.vbox.setContentsMargins(0,0,0,0)
self.press_control = 0
self.setCentralWidget(self.central)
self.resize(800,500)
self.show()
def eventFilter(self, obj, e):
#hovermoveevent
if e.type() == 129:
if self.press_control == 0:
self.pos_control(e)#cursor position control for cursor shape setup
#mousepressevent
if e.type() == 2:
self.press_control = 1
self.origin = self.mapToGlobal(e.pos())
self.ori_geo = self.geometry()
#mousereleaseevent
if e.type() == 3:
self.press_control = 0
self.pos_control(e)
#mosuemoveevent
if e.type() == 5:
if self.cursor().shape() != Qt.ArrowCursor:
self.resizing(self.origin, e, self.ori_geo, self.value)
return True
def pos_control(self, e):
rect = self.rect()
top_left = rect.topLeft()
top_right = rect.topRight()
bottom_left = rect.bottomLeft()
bottom_right = rect.bottomRight()
pos = e.pos()
#top catch
if pos in QRect(QPoint(top_left.x()+5,top_left.y()), QPoint(top_right.x()-5,top_right.y()+5)):
self.setCursor(Qt.SizeVerCursor)
self.value = 1
#bottom catch
elif pos in QRect(QPoint(bottom_left.x()+5,bottom_left.y()), QPoint(bottom_right.x()-5,bottom_right.y()-5)):
self.setCursor(Qt.SizeVerCursor)
self.value = 2
#right catch
elif pos in QRect(QPoint(top_right.x()-5,top_right.y()+5), QPoint(bottom_right.x(),bottom_right.y()-5)):
self.setCursor(Qt.SizeHorCursor)
self.value = 3
#left catch
elif pos in QRect(QPoint(top_left.x()+5,top_left.y()+5), QPoint(bottom_left.x(),bottom_left.y()-5)):
self.setCursor(Qt.SizeHorCursor)
self.value = 4
#top_right catch
elif pos in QRect(QPoint(top_right.x(),top_right.y()), QPoint(top_right.x()-5,top_right.y()+5)):
self.setCursor(Qt.SizeBDiagCursor)
self.value = 5
#botom_left catch
elif pos in QRect(QPoint(bottom_left.x(),bottom_left.y()), QPoint(bottom_left.x()+5,bottom_left.y()-5)):
self.setCursor(Qt.SizeBDiagCursor)
self.value = 6
#top_left catch
elif pos in QRect(QPoint(top_left.x(),top_left.y()), QPoint(top_left.x()+5,top_left.y()+5)):
self.setCursor(Qt.SizeFDiagCursor)
self.value = 7
#bottom_right catch
elif pos in QRect(QPoint(bottom_right.x(),bottom_right.y()), QPoint(bottom_right.x()-5,bottom_right.y()-5)):
self.setCursor(Qt.SizeFDiagCursor)
self.value = 8
#default
else:
self.setCursor(Qt.ArrowCursor)
def resizing(self, ori, e, geo, value):
#top_resize
if self.value == 1:
last = self.mapToGlobal(e.pos())-ori
first = geo.height()
first -= last.y()
Y = geo.y()
Y += last.y()
if first > self.minimumHeight():
self.setGeometry(geo.x(), Y, geo.width(), first)
#bottom_resize
if self.value == 2:
last = self.mapToGlobal(e.pos())-ori
first = geo.height()
first += last.y()
self.resize(geo.width(), first)
#right_resize
if self.value == 3:
last = self.mapToGlobal(e.pos())-ori
first = geo.width()
first += last.x()
self.resize(first, geo.height())
#left_resize
if self.value == 4:
last = self.mapToGlobal(e.pos())-ori
first = geo.width()
first -= last.x()
X = geo.x()
X += last.x()
if first > self.minimumWidth():
self.setGeometry(X, geo.y(), first, geo.height())
#top_right_resize
if self.value == 5:
last = self.mapToGlobal(e.pos())-ori
first_width = geo.width()
first_height = geo.height()
first_Y = geo.y()
first_width += last.x()
first_height -= last.y()
first_Y += last.y()
if first_height > self.minimumHeight():
self.setGeometry(geo.x(), first_Y, first_width, first_height)
#bottom_right_resize
if self.value == 6:
last = self.mapToGlobal(e.pos())-ori
first_width = geo.width()
first_height = geo.height()
first_X = geo.x()
first_width -= last.x()
first_height += last.y()
first_X += last.x()
if first_width > self.minimumWidth():
self.setGeometry(first_X, geo.y(), first_width, first_height)
#top_left_resize
if self.value == 7:
last = self.mapToGlobal(e.pos())-ori
first_width = geo.width()
first_height = geo.height()
first_X = geo.x()
first_Y = geo.y()
first_width -= last.x()
first_height -= last.y()
first_X += last.x()
first_Y += last.y()
if first_height > self.minimumHeight() and first_width > self.minimumWidth():
self.setGeometry(first_X, first_Y, first_width, first_height)
#bottom_right_resize
if self.value == 8:
last = self.mapToGlobal(e.pos())-ori
first_width = geo.width()
first_height = geo.height()
first_width += last.x()
first_height += last.y()
self.setGeometry(geo.x(), geo.y(), first_width, first_height)
app = QApplication([])
window = main()
window.installEventFilter(window)
app.exec()
Upvotes: 5
Reputation: 3068
You need to handle the mouse events yourself.
mousePressEvent
, which will keep the place where we last clicked on the windowmouseMoveEvent
, which will calculate the distance between the last clicked point and the current mouse location. We will move the window according to this distance.This is the fixed code:
import sys
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
class cssden(QMainWindow):
def __init__(self):
super().__init__()
# <MainWindow Properties>
self.setFixedSize(320, 450)
self.setStyleSheet("QMainWindow{background-color: darkgray;border: 1px solid black}")
self.setWindowFlags(Qt.FramelessWindowHint)
self.center()
# </MainWindow Properties>
# <Label Properties>
self.lbl = QLabel(self)
self.lbl.setText("test")
self.lbl.setStyleSheet("QLabel{background-color: rgb(0,0,0); border: 1px solid red; color: rgb(255,255,255); font: bold italic 20pt 'Times New Roman';}")
self.lbl.setGeometry(5, 5, 60, 40)
# </Label Properties>
self.oldPos = self.pos()
self.show()
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = cssden()
sys.exit(app.exec_())
Upvotes: 31