I'm working with pyqt5 and qt designer in python 3.7.x and my draggable QLabels don't seems to work. I'm trying to set de Labels as draggable and drop them into another Label, but my code doesn't work, I made the window in qt designer and also defined the Lebels there, but when I try to "transform" the QLabels into a draggable objects nothing happens. Here is some of my code and I'll explain:
class Window(window_name, base_class):
def __init__(self):
super().__init__()
self.setupUi(self)
self.penguin_list = (
self.cyan,
self.red,
self.yellow,
self.purple,
self.green
) # This tuple is made out of the QLabel created on qt designer that i want to drag
def mousePressEvent(self, event):
# Here I tried to set the QLabel that I want to drag (the one the mouse pressed)
if event.button() == Qt.LeftButton:
for penguin in self.penguin_list:
if penguin.underMouse():
self.penguin = penguin
self.drag_start_position = event.pos()
def mouseMoveEvent(self, event):
# Here is when I tried to convert the QLavel into draggable
# Also the QLabel appears in the top left corner (sometimes) with a white background
# And also the drop part doesn't work and I can not drop the QLabel
if not (event.buttons() & Qt.LeftButton):
return
if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
return
drag = QDrag(self.penguin)
mimedata = QMimeData()
mimedata.setImageData(self.penguin.pixmap())
drag.setMimeData(mimedata)
pixmap = QPixmap(self.penguin.size())
painter = QPainter(pixmap)
painter.drawPixmap(self.penguin.rect(), self.penguin.grab())
painter.end()
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos())
drag.exec_(Qt.CopyAction | Qt.MoveAction)
Overall I wanna make a copy of the QLabel when i click on it and drop it (pasted) in other QLabel that is in other QFrame.
Related
I want to create a draggable and resizable frameless window in Pyside6 by rewritting the mouseEvent and resizeEvent.And try to use QSizeGrip to control the shape of window.
Drag and resize, I can implement both functions alone, but there is a problem when they are combined.
when I resize the window after dragging, the position will be wrong. I want to know what's the wrong in this codeļ¼
import sys
from PySide6.QtCore import *
from PySide6.QtWidgets import *
from PySide6.QtGui import *
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.text = QLabel("Hello World",alignment=Qt.AlignCenter)
self.layout =QVBoxLayout(self)
self.layout.addWidget(self.text)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.gripSize = 16
self.grips = []
for i in range(4):
grip = QSizeGrip(self)
grip.resize(self.gripSize, self.gripSize)
self.grips.append(grip)
def resizeEvent(self, event):
QWidget.resizeEvent(self, event)
rect = self.rect()
# top left grip doesn't need to be moved...
# top right
self.grips[1].move(rect.right() - self.gripSize, 0)
# bottom right
self.grips[2].move(
rect.right() - self.gripSize, rect.bottom() - self.gripSize)
# bottom left
self.grips[3].move(0, rect.bottom() - self.gripSize)
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([])
By default, QSizeGrip interfaces with the OS for the actual resizing as soon as it's activated (by pressing the left mouse button on it).
The result is that, after that, all mouse move events are intercepted by the system until the button is released. Since the button release is also intercepted by the system (to know that the resizing has been completed), QSizeGrip will be able to handle again mouse events only after the button release; since the previous condition was the mouse button press, it will receive a MouseMove event, and, by defaults, those events are ignored by widgets if they don't handle it.
If a mouse event is ignored, it is propagated to its parent(s), which in this case is your MyWidget.
Unfortunately, your assumption is that you only get mouse move events only after a button press, but, due to what explained above, this is not the case: you will not receive a mouse button press (it was handled by the size grip), but only a mouse move (since it's been ignored by the size grip).
Now, there are two cases:
you previously moved the window, so there is an oldPos based on the previous start mouse position, and the window will be moved using the wrong parameters;
you only resized the window since startup, and the program will crash because there was no oldPos attribute;
There are various possible solutions, but the simple one is to create a default oldPos attribute having a None value, set it in the mouse press, check if self.oldPos is not None in the mouse move (and eventually move) and, most importantly, restore self.oldPos = None in the mouse release.
Note that it's usually better to move the window only using a single button (the convention is the left one, but the middle one is not uncommon)
class MyWidget(QWidget):
oldPos = None
# ...
def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self.oldPos = event.globalPos()
def mouseMoveEvent(self, event):
if self.oldPos is not None:
delta = event.globalPos() - self.oldPos
self.move(self.pos() + delta)
self.oldPos = event.globalPos()
def mouseReleaseEvent(self, event):
self.oldPos = None
Note: QPoint + QPoint is already a QPoint, and move() accepts a QPoint by default, so there's no need to sum x and y coordinates individually.
I want to put a QLineEdit and QLable to the same cell in QTableWidget. This cell widget has created the code below I modified from the internet.
class HiddenLabel(QLabel):
'''
QLable hide when mouse pressed
'''
def __init__(self, buddy, taskline, parent = None):
super(HiddenLabel, self).__init__(parent)
self.setFixedHeight(30)
self.buddy = buddy
self.taskline = taskline
# When it's clicked, hide itself and show its buddy
def mousePressEvent(self, event):
# left click to edit
if event.button() == QtCore.Qt.LeftButton:
self.hide()
self.buddy.setText(self.taskline.plain_text)
self.buddy.show()
self.buddy.setFocus() # Set focus on buddy so user doesn't have to click again
class EditableCell(QWidget):
'''
QLineEdit show when HiddenLabel is hidden
'''
def __init__(self, taskline, parent = None):
super(EditableCell, self).__init__(parent)
self.taskline = taskline
# Create ui
self.myEdit = QLineEdit()
self.myEdit.setFixedHeight(30)
self.myEdit.hide() # Hide line edit
self.myEdit.editingFinished.connect(self.textEdited)
# Create our custom label, and assign myEdit as its buddy
self.myLabel = HiddenLabel(self.myEdit, self.taskline)
self.myLabel.setText(self.taskline.enrich_text())
# Change vertical size policy so they both match and you don't get popping when switching
#self.myLabel.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
# Put them under a layout together
hLayout = QHBoxLayout()
hLayout.addWidget(self.myLabel)
hLayout.addWidget(self.myEdit)
self.setLayout(hLayout)
def textEdited(self):
# If the input is left empty, revert back to the label showing
print('edit finished')
print(self.myEdit.text())
taskline = TaskLine()
taskline.parser(self.myEdit.text())
self.taskline = taskline
self.myLabel.setText(taskline.enrich_text())
self.myEdit.hide()
self.myLabel.show()
The cell will change between QLineEdit and QLabel by left click.
As figured in the screenshot, I want to remove the blank space between the cell border and cell widget.
I think it can be adjusted by style setting, but I didn't find any useful documents about Qt style setting. I hope someone could give some use
You must set the layout margins to 0:
hLayout.setContentsMargins(0, 0, 0, 0)
since as the docs point out they are dependent on the style and platform:
void QLayout::setContentsMargins(int left, int top, int right, int
bottom)
Sets the left, top, right, and bottom margins to use around
the layout.
By default, QLayout uses the values provided by the style. On most
platforms, the margin is 11 pixels in all directions.
When I drag my QPushButton, it disappears until dropped. I want to show the button all the time while it is being dragged. How to do that?
Downwards my Button that is being dragged around including the QDrag object.
Happy to share more code if needed :)
A photo of my screen
class DraggableCodeBlock(QPushButton):
def __init__(self, width, height, offset_left, offset_top, parent, command):
super().__init__(parent=parent)
self.parent = parent
self.setText(command)
self.show()
def mouseMoveEvent(self, e):
if e.buttons() != Qt.LeftButton:
return
mimeData = QMimeData()
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(Qt.MoveAction)
super(DraggableCodeBlock, self).mouseMoveEvent(e)
def mousePressEvent(self, e):
super().mousePressEvent(e)
if e.button() == Qt.LeftButton or not(self.is_mobile):
print('press')
you must set the image you want to show through setPixmap(), to get the image of the widget you should use grab():
drag = QDrag(self)
drag.setPixmap(self.grab())
I'm working on an opensource markdown supported minimal note taking application for Windows/Linux. I'm trying to remove the title bar and add my own buttons. I want something like, a title bar with only two custom buttons as shown in the figure
Currently I have this:
I've tried modifying the window flags:
With not window flags, the window is both re-sizable and movable. But no custom buttons.
Using self.setWindowFlags(QtCore.Qt.FramelessWindowHint), the window has no borders, but cant move or resize the window
Using self.setWindowFlags(QtCore.Qt.CustomizeWindowHint), the window is resizable but cannot move and also cant get rid of the white part at the top of the window.
Any help appreciated. You can find the project on GitHub here.
Thanks..
This is my python code:
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, uic
import sys
import os
import markdown2 # https://github.com/trentm/python-markdown2
from PyQt5.QtCore import QRect
from PyQt5.QtGui import QFont
simpleUiForm = uic.loadUiType("Simple.ui")[0]
class SimpleWindow(QtWidgets.QMainWindow, simpleUiForm):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.markdown = markdown2.Markdown()
self.css = open(os.path.join("css", "default.css")).read()
self.editNote.setPlainText("")
#self.noteView = QtWebEngineWidgets.QWebEngineView(self)
self.installEventFilter(self)
self.displayNote.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
#self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
def eventFilter(self, object, event):
if event.type() == QtCore.QEvent.WindowActivate:
print("widget window has gained focus")
self.editNote.show()
self.displayNote.hide()
elif event.type() == QtCore.QEvent.WindowDeactivate:
print("widget window has lost focus")
note = self.editNote.toPlainText()
htmlNote = self.getStyledPage(note)
# print(note)
self.editNote.hide()
self.displayNote.show()
# print(htmlNote)
self.displayNote.setHtml(htmlNote)
elif event.type() == QtCore.QEvent.FocusIn:
print("widget has gained keyboard focus")
elif event.type() == QtCore.QEvent.FocusOut:
print("widget has lost keyboard focus")
return False
The UI file is created in the following hierarchy
Here are the steps you just gotta follow:
Have your MainWindow, be it a QMainWindow, or QWidget, or whatever [widget] you want to inherit.
Set its flag, self.setWindowFlags(Qt.FramelessWindowHint)
Implement your own moving around.
Implement your own buttons (close, max, min)
Implement your own resize.
Here is a small example with move around, and buttons implemented. You should still have to implement the resize using the same logic.
import sys
from PyQt5.QtCore import QPoint
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import 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_())
Here are some tips:
Option 1:
Have a QGridLayout with widget in each corner and side(e.g. left, top-left, menubar, top-right, right, bottom-right, bottom and bottom left)
With the approach (1) you would know when you are clicking in each border, you just got to define each one size and add each one on their place.
When you click on each one treat them in their respective ways, for example, if you click in the left one and drag to the left, you gotta resize it larger and at the same time move it to the left so it will appear to be stopped at the right place and grow width.
Apply this reasoning to each edge, each one behaving in the way it has to.
Option 2:
Instead of having a QGridLayout you can detect in which place you are clicking by the click pos.
Verify if the x of the click is smaller than the x of the moving pos to know if it's moving left or right and where it's being clicked.
The calculation is made in the same way of the Option1
Option 3:
Probably there are other ways, but those are the ones I just thought of. For example using the CustomizeWindowHint you said you are able to resize, so you just would have to implement what I gave you as example. BEAUTIFUL!
Tips:
Be careful with the localPos(inside own widget), globalPos(related to your screen). For example: If you click in the very left of your left widget its 'x' will be zero, if you click in the very left of the middle(content)it will be also zero, although if you mapToGlobal you will having different values according to the pos of the screen.
Pay attention when resizing, or moving, when you have to add width or subtract, or just move, or both, I'd recommend you to draw on a paper and figure out how the logic of resizing works before implementing it out of blue.
GOOD LUCK :D
While the accepted answer can be considered valid, it has some issues.
using setGeometry() is not appropriate (and the reason for using it was wrong) since it doesn't consider possible frame margins set by the style;
the position computation is unnecessarily complex;
resizing the title bar to the total width is wrong, since it doesn't consider the buttons and can also cause recursion problems in certain situations (like not setting the minimum size of the main window); also, if the title is too big, it makes impossible to resize the main window;
buttons should not accept focus;
setting a layout creates a restraint for the "main widget" or layout, so the title should not be added, but the contents margins of the widget should be used instead;
I revised the code to provide a better base for the main window, simplify the moving code, and add other features like the Qt windowTitle() property support, standard QStyle icons for buttons (instead of text), and proper maximize/normal button icons. Note that the title label is not added to the layout.
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
self.titleBar = MyBar(self)
self.setContentsMargins(0, self.titleBar.height(), 0, 0)
self.resize(640, self.titleBar.height() + 480)
def changeEvent(self, event):
if event.type() == event.WindowStateChange:
self.titleBar.windowStateChanged(self.windowState())
def resizeEvent(self, event):
self.titleBar.resize(self.width(), self.titleBar.height())
class MyBar(QWidget):
clickPos = None
def __init__(self, parent):
super(MyBar, self).__init__(parent)
self.setAutoFillBackground(True)
self.setBackgroundRole(QPalette.Shadow)
# alternatively:
# palette = self.palette()
# palette.setColor(palette.Window, Qt.black)
# palette.setColor(palette.WindowText, Qt.white)
# self.setPalette(palette)
layout = QHBoxLayout(self)
layout.setContentsMargins(1, 1, 1, 1)
layout.addStretch()
self.title = QLabel("My Own Bar", self, alignment=Qt.AlignCenter)
# if setPalette() was used above, this is not required
self.title.setForegroundRole(QPalette.Light)
style = self.style()
ref_size = self.fontMetrics().height()
ref_size += style.pixelMetric(style.PM_ButtonMargin) * 2
self.setMaximumHeight(ref_size + 2)
btn_size = QSize(ref_size, ref_size)
for target in ('min', 'normal', 'max', 'close'):
btn = QToolButton(self, focusPolicy=Qt.NoFocus)
layout.addWidget(btn)
btn.setFixedSize(btn_size)
iconType = getattr(style,
'SP_TitleBar{}Button'.format(target.capitalize()))
btn.setIcon(style.standardIcon(iconType))
if target == 'close':
colorNormal = 'red'
colorHover = 'orangered'
else:
colorNormal = 'palette(mid)'
colorHover = 'palette(light)'
btn.setStyleSheet('''
QToolButton {{
background-color: {};
}}
QToolButton:hover {{
background-color: {}
}}
'''.format(colorNormal, colorHover))
signal = getattr(self, target + 'Clicked')
btn.clicked.connect(signal)
setattr(self, target + 'Button', btn)
self.normalButton.hide()
self.updateTitle(parent.windowTitle())
parent.windowTitleChanged.connect(self.updateTitle)
def updateTitle(self, title=None):
if title is None:
title = self.window().windowTitle()
width = self.title.width()
width -= self.style().pixelMetric(QStyle.PM_LayoutHorizontalSpacing) * 2
self.title.setText(self.fontMetrics().elidedText(
title, Qt.ElideRight, width))
def windowStateChanged(self, state):
self.normalButton.setVisible(state == Qt.WindowMaximized)
self.maxButton.setVisible(state != Qt.WindowMaximized)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.clickPos = event.windowPos().toPoint()
def mouseMoveEvent(self, event):
if self.clickPos is not None:
self.window().move(event.globalPos() - self.clickPos)
def mouseReleaseEvent(self, QMouseEvent):
self.clickPos = None
def closeClicked(self):
self.window().close()
def maxClicked(self):
self.window().showMaximized()
def normalClicked(self):
self.window().showNormal()
def minClicked(self):
self.window().showMinimized()
def resizeEvent(self, event):
self.title.resize(self.minButton.x(), self.height())
self.updateTitle()
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
layout = QVBoxLayout(mw)
widget = QTextEdit()
layout.addWidget(widget)
mw.show()
mw.setWindowTitle('My custom window with a very, very long title')
sys.exit(app.exec_())
This is for the people who are going to implement custom title bar in PyQt6 or PySide6
The below changes should be done in the answer given by #musicamante
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
# self.clickPos = event.windowPos().toPoint()
self.clickPos = event.scenePosition().toPoint()
def mouseMoveEvent(self, event):
if self.clickPos is not None:
# self.window().move(event.globalPos() - self.clickPos)
self.window().move(event.globalPosition().toPoint() - self.clickPos)
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
# sys.exit(app.exec_())
sys.exit(app.exec())
References:
QMouseEvent.globalPosition(),
QMouseEvent.scenePosition()
This method of moving Windows with Custom Widget doesn't work with WAYLAND. If anybody has a solution for that please post it here for future reference
Working functions for WAYLAND and PyQT6/PySide6 :
def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self._move()
return super().mousePressEvent(event)
def _move(self):
window = self.window().windowHandle()
window.startSystemMove()
Please check.
Is it possible to scale (or "zoom") a QTextEdit area? I believe I read that placing QTextEdit inside QLayout can allow for scaling of the QTextEdit area, though did not find how to implement it. Couple of options...
CTRL + Roll of Mouse Wheel
Running the code below, holding down the CTRL (control) key and rolling the mouse wheel, the event is captured and the text does scale (at least on Windows), however, as the text grows larger the wheel has to move further and further for very much effect, so one goal is to be able to modify that somehow, maybe some math to increase the increments to a greater degree on increases in the plus direction.
(The setReadOnly()'s below are because it would seem textEdit has to be ReadOnly(False) for the mouse event to be captured, then True to be able to scale during roll of the mouse wheel, so it is then set back to original state of False again on release of the CTRL key).
Toolbar Button Click
The other option is toolbar buttons for zoom in and out.
onZoomInClicked() is called.
Some current problems with the code below
1. It prints: QLayout: Attempting to add QLayout "" to MainWindow "", which already has a layout and I don't have my head wrapped around that yet.
2. QtGui.QTextEdit(self.formLayout) instead of (self) to place the textEdit area inside the layout produces TypeError: 'PySide.QtGui.QTextEdit' called with wrong argument types
3. wheelEvent() could use some way to modify event.delta() maybe?
4. The toolbar button (text only) will currently run its def when clicked, however it only contains a print statement.
from PySide import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.formLayout = QtGui.QFormLayout(self)
self.textEdit = QtGui.QTextEdit(self)
self.toolBar = QtGui.QToolBar(self)
self.actionZoomIn = QtGui.QAction(self)
self.textEdit.setHtml('<font color=blue>Hello <b>world</b></font>')
self.setCentralWidget(self.textEdit)
self.addToolBar(self.toolBar)
self.toolBar.addAction(self.actionZoomIn)
self.actionZoomIn.setText('Zoom In')
self.actionZoomIn.connect(self.actionZoomIn,
QtCore.SIGNAL('triggered()'), self.onZoomInClicked)
def onZoomInClicked(self):
print "onZoomInClicked(self) needs code"
def wheelEvent(self, event):
print "wheelEvent() captured"
if (event.modifiers() & QtCore.Qt.ControlModifier):
self.textEdit.setReadOnly(True)
event.accept()
def keyReleaseEvent(self, evt):
if evt.key() == QtCore.Qt.Key_Control:
self.textEdit.setReadOnly(False)
if __name__ == '__main__':
app = QtGui.QApplication([])
frame = MainWindow()
frame.show()
app.exec_()
I've been grappling with this for days so would be great to have the more customizable QTextEdit scale/zoom working if it is even possible.
The two error messages can be expained as follows:
The QMainWidget automatically gets a layout, so the QFormLayout is redundant. If you want to add a layout, create a QWidget to be the central widget and make it the parent of the new layout. Other widgets can then be added to that new layout.
The parent of a QWidget subclass must itself be QWidget subclass, which QFormLayout isn't.
I've modified your example so that it does most of what you asked for. Note that QTextEdit.zoomIn and QTextEdit.zoomOut both take a range argument for controlling the degree of zoom.
from PySide import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.textEdit = Editor(self)
self.toolBar = QtGui.QToolBar(self)
self.actionZoomIn = QtGui.QAction('Zoom In', self)
self.actionZoomOut = QtGui.QAction('Zoom Out', self)
self.textEdit.setHtml('<font color=blue>Hello <b>world</b></font>')
self.setCentralWidget(self.textEdit)
self.addToolBar(self.toolBar)
self.toolBar.addAction(self.actionZoomIn)
self.toolBar.addAction(self.actionZoomOut)
self.actionZoomIn.triggered.connect(self.onZoomInClicked)
self.actionZoomOut.triggered.connect(self.onZoomOutClicked)
def onZoomInClicked(self):
self.textEdit.zoom(+1)
def onZoomOutClicked(self):
self.textEdit.zoom(-1)
class Editor(QtGui.QTextEdit):
def __init__(self, parent=None):
super(Editor, self).__init__(parent)
def zoom(self, delta):
if delta < 0:
self.zoomOut(1)
elif delta > 0:
self.zoomIn(5)
def wheelEvent(self, event):
if (event.modifiers() & QtCore.Qt.ControlModifier):
self.zoom(event.delta())
else:
QtGui.QTextEdit.wheelEvent(self, event)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()