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_())
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_())
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()
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

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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With