This paper uses PYTHON3+PYQT5 to implement the page designer application of the Python Qt Gui fast program, using Qgraphicsview,qgraphicsscene,qgraphicsitem, This program contains multiple pages of text, pictures and boxes. Some graphics classes are obsolete in PyQt5, so this code changes a lot. The changes to the main class or method are as follows:
Qmatrix==>qtransform
Setmatrix==>settransform
Rotate ==> setrotation
In this case, the Wheelevent method is overridden because Event.delta () is obsolete:
def wheelevent (self, event):
#factor = 1.41 * * (-event.delta ()/240.0)
#factor = 1.41 * * (-abs (EVENT.STARTX ()-eve NT.Y ())/240.0)
factor = Event.angledelta (). Y ()/120.0
if Event.angledelta (). Y ()/120.0 > 0:
factor=2
else:
factor=0.5
Self.scale (factor, factor)
To keep the code readable, add a class:
Class Graphicspixmapitem (Qgraphicspixmapitem): #add by Yangrongdong
def __init__ (self,pixmap):
Super (Qgraphicspixmapitem, self). __init__ (Pixmap)
In this case there is also a button that contains a menu:
if text = = "&align":
menu = Qmenu (self) for
text, Arg in (
("Align &left", Qt.alignleft),
("Align &right ", Qt.alignright),
(" Align &top ", Qt.aligntop),
(" Align &bottom ", Qt.alignbottom)):
Wrapper = Functools.partial (Self.setalignment, Arg)
self.wrapped.append (wrapper)
menu.addaction (text, Wrapper)
Button.setmenu (menu)
In this case, the qstyleoptiongraphicsitem.levelofdetail is also obsolete and is rewritten as follows:
Option.levelofdetailfromtransform (Self.transform ())
The following is the complete code:
#!/usr/bin/env python3 Import functools import random import sys from pyqt5.qtcore import (Qbytearray, Qdatastream, Qfil E, Qfileinfo, Qiodevice, Qpoint, qpointf, QRECTF, Qt) from pyqt5.qtwidgets import (Qapplication, Qdialog, Qdialogbuttonbox, Qfiledialog, Qfontcombobox, qgraphic
Sitem, Qgraphicspixmapitem, Qgraphicsscene, Qgraphicstextitem, Qgraphicsview, Qgridlayout, Qhboxlayout, Qlabel, Qmenu, Qmessagebox,qpushbutton, Qspinbox, QSt YLE, Qtextedit, qvboxlayout) from Pyqt5.qtgui import Qfont,qcursor,qfontmetrics,qtransform,qpainter,qpen,qpixmap from Pyqt5.qtprintsupport import Qprinter,qprintdialog MAC = True try:from Pyqt5.qtgui import Qt_mac_set_native_menubar E Xcept Importerror:mac = False #PageSize = (595, 842) # A4 in points PageSize = (612, 792) # US letter in points Poin Tsize = MagicNumber = 0x70616765 FileVersion = 1 Dirty = False class Textitemdlg (qdialog): Def __init__ (self, item=none, Position=none, SC Ene=none, Parent=none): Super (Qdialog, self). __init__ (parent) Self.item = Item Self.position = PO
Sition self.scene = Scene self.editor = Qtextedit () self.editor.setAcceptRichText (False)
Self.editor.setTabChangesFocus (True) Editorlabel = Qlabel ("&text:") Editorlabel.setbuddy (Self.editor) Self.fontcombobox = Qfontcombobox () Self.fontComboBox.setCurrentFont (Qfont ("Times", pointsize)) fo
Ntlabel = Qlabel ("&font:") Fontlabel.setbuddy (self.fontcombobox) Self.fontspinbox = Qspinbox () Self.fontSpinBox.setAlignment (qt.alignright| Qt.alignvcenter) Self.fontSpinBox.setRange (6, 280) Self.fontSpinBox.setValue (pointsize) Fontsizela Bel = Qlabel ("&size:") Fontsizelabel.setbuddy (self.fontspinbox) Self.buttonbox =Qdialogbuttonbox (qdialogbuttonbox.ok| Qdialogbuttonbox.cancel) Self.buttonBox.button (Qdialogbuttonbox.ok). setenabled (False) if Self.item is not None:self.editor.setPlainText (Self.item.toPlainText ()) Self.fontComboBox.setCurrentFont (self.ite M.font ()) Self.fontSpinBox.setValue (Self.item.font (). pointsize ()) layout = Qgridlayout () layo Ut.addwidget (editorlabel, 0, 0) layout.addwidget (self.editor, 1, 0, 1, 6) layout.addwidget (Fontlabel, 2, 0 ) Layout.addwidget (Self.fontcombobox, 2, 1, 1, 2) layout.addwidget (Fontsizelabel, 2, 3) Layout.add
Widget (Self.fontspinbox, 2, 4, 1, 2) layout.addwidget (Self.buttonbox, 3, 0, 1, 6) self.setlayout (layout) Self.fontComboBox.currentFontChanged.connect (Self.updateui) self.fontSpinBox.valueChanged.connect (self.up
Dateui) Self.editor.textChanged.connect (Self.updateui) Self.buttonBox.accepted.connect (self.accept) self.buttonBox.rejected.connect (self.reject) Self.setwi Ndowtitle ("Page Designer-{0} Text Item". Format ("Add" if Self.item is None else "Edit") self.up Dateui () def updateui (self): Font = Self.fontComboBox.currentFont () font.setpointsize (self.fontspinb Ox.value ()) self.editor.document (). Setdefaultfont (font) Self.buttonBox.button (Qdialogbuttonbox.ok). Setenab LED (BOOL (Self.editor.toPlainText ())) def accept (self): if Self.item is None:se Lf.item = Textitem ("", Self.position, self.scene) font = Self.fontComboBox.currentFont () font.setpointsize
(Self.fontSpinBox.value ()) Self.item.setFont (font) self.item.setPlainText (Self.editor.toPlainText ()) Self.item.update () global Dirty Dirty = True qdialog.accept (self) class Textitem (Qgraphics Textitem): Def __iniT__ (self, text, position, scene, Font=qfont ("Times", Pointsize), Matrix=qtransform ()): Super (text
Item, self). __init__ (text) self.setflags (qgraphicsitem.itemisselectable|
qgraphicsitem.itemismovable) Self.setfont (font) self.setpos (position) self.settransform (matrix) Scene.clearselection () Scene.additem (self) self.setselected (True) Global Dirty Dirty
= True def parentwidget (self): return Self.scene (). Views () [0] def itemchange (self, Change, variant): If change!= QGraphicsItem.ItemSelectedChange:global Dirty Dirty = True return QG Raphicstextitem.itemchange (self, change, variant) def mousedoubleclickevent (Self, event): Dialog = Textitemd LG (self, Self.parentwidget ()) dialog.exec_ () class Graphicspixmapitem (Qgraphicspixmapitem): #add by Yang
Rongdong def __init__ (self,pixmap): Super (Qgraphicspixmapitem, self). __init__ (Pixmap) class Boxitem (Qgraphicsitem): Def __init__ (self, position, s
Cene, Style=qt.solidline, Rect=none, Matrix=qtransform ()): Super (Boxitem, self). __init__ ()
Self.setflags (qgraphicsitem.itemisselectable|
qgraphicsitem.itemismovable| qgraphicsitem.itemisfocusable) If rect is None:rect = QRECTF ( -10 * pointsize,-pointsize, * PointS ize, 2 * pointsize) Self.rect = rect Self.style = Style Self.setpos (posi tion) self.settransform (matrix) scene.clearselection () Scene.additem (self) self.setselecte D (True) Self.setfocus () global Dirty Dirty = True def parentwidget (self): return sel F.scene (). Views () [0] def boundingrect (self): return self.rect.adjusted ( -2,-2, 2, 2) def paint (self, p
Ainter, option, widget): Pen = Qpen (Self.style) pen.setcolor (Qt.black) pen.setwidth (1) if Option.state & Qstyle . State_Selected:pen.setColor (qt.blue) painter.setpen (pen) painter.drawrect (Self.rect) de
F ItemChange (self, Change, variant): If change!= QGraphicsItem.ItemSelectedChange:global Dirty Dirty = True return Qgraphicsitem.itemchange (self, change, variant) def contextmenuevent (self, event) : wrapped = [] menu = Qmenu (Self.parentwidget ()) for text, param in (("&solid
", Qt.solidline), (" &dashed ", Qt.dashline), (" d&otted ", Qt.dotline), ("d&ashdotted", Qt.dashdotline), ("dashdo&tdotted", Qt.dashdotdotline)): wrapper =
Functools.partial (Self.setstyle, param) wrapped.append (wrapper) menu.addaction (text, wrapper) MENU.EXEC_ (Event.scReenpos ()) def setStyle (self, style): Self.style = Style self.update () global Dirty Dirty = True def keypressevent (Self, event): Factor = POINTSIZE/4 changed = False if event . Modifiers () & Qt.ShiftModifier:if event.key () = = Qt.Key_Left:self.rect.setRight (self.re Ct.right ()-factor) changed = True elif Event.key () = = Qt.Key_Right:self.rec
T.setright (Self.rect.right () + factor) changed = True elif Event.key () = = Qt.key_up: Self.rect.setBottom (Self.rect.bottom ()-factor) changed = True elif event.key () = Qt. Key_Down:self.rect.setBottom (Self.rect.bottom () + factor) changed = True if Chang Ed:self.update () global Dirty Dirty = True else:QGraphicsItem.ke Ypressevent (self, event)
Class Graphicsview (Qgraphicsview): Def __init__ (self, Parent=none): Super (Graphicsview, self). __init__ (Par ENT) Self.setdragmode (Qgraphicsview.rubberbanddrag) self.setrenderhint (qpainter.antialiasing) Self . Setrenderhint (qpainter.textantialiasing) def wheelevent (Self, event): #factor = 1.41 * * (-event.delta ()/2
40.0) factor = Event.angledelta (). Y ()/120.0 if Event.angledelta (). Y ()/120.0 > 0:factor=2 else:factor=0.5 Self.scale (factor, Factor) class MainForm (Qdialog): Def __init__ (self, Parent=none): Super (MainForm, self). __init__ (parent) Self.filename = "" Self.copieditem = Qbytea
Rray () Self.pasteoffset = 5 Self.prevpoint = Qpoint () Self.addoffset = 5 Self.borders = [] Self.printer = Qprinter (qprinter.highresolution) self.printer.setPageSize (qprinter.letter) Self
. View = Graphicsview () Self.scene = Qgraphicsscene (self) self.scene.setSceneRect (0, 0, pagesize[0], pagesize[1]) self.addb Orders () Self.view.setScene (self.scene) self.wrapped = [] # Needed to keep wrappers (alive) buttonl Ayout = Qvboxlayout () for text, slot in (("Add &text", Self.addtext), ("Add & Amp
Box ", Self.addbox), (" Add pi&xmap ", Self.addpixmap), (" &align ", None),
("©", Self.copy), ("C&ut", Self.cut), ("&paste", Self.paste), ("&delete ...", Self.delete), ("&rotate", Self.rotate), ("Pri&nt ..."), Self.print_), ("&open ...", Self.open), ("&save", Self.save), ("&am P Quit ", self.accept)): Button = Qpushbutton (text) if not MAC:button.setFocusPolicy
(Qt.nofocus) If slot is not None:button.clicked.connect (slot) if text = "&align":
menu = Qmenu (self) for text, Arg in (("Align &left", Qt.alignleft),
("Align &right", Qt.alignright), ("Align &top", Qt.aligntop), ("Align &bottom", Qt.alignbottom)): wrapper = Functools.partial (Self.setalignment, ARG) self.wrapped.append (wrapper) menu.addaction (text, wrapper) BU Tton.setmenu (menu) if text = = "Pri&nt ...": Buttonlayout.addstretch (5) if text = = "&quit": Buttonlayout.addstretch (1) Buttonlayout.addwidget (button) buttonlayout . Addstretch () layout = Qhboxlayout () layout.addwidget (Self.view, 1) layout.addlayout (buttonlayout ) self.setlayout(layout) fm = Qfontmetrics (Self.font ()) Self.resize (Self.scene.width () + fm.width ("Delete ...) ") + self.scene.height () +) Self.setwindowtitle (" Page Designer ") def addborders (s ELF): Self.borders = [] rect = QRECTF (0, 0, pagesize[0], pagesize[1]) self.borders.append (self.sce
Ne.addrect (Rect, qt.yellow)) margin = 5.25 * pointsize self.borders.append (Self.scene.addRect ( rect.adjusted (margin, margin,-margin,-margin), Qt.yellow)) def removeborders (self): W
Hile self.borders:item = Self.borders.pop () Self.scene.removeItem (item) del item
Def reject (self): self.accept () def accept (self): Self.offersave () qdialog.accept (self) def offersave (self): if (Dirty and qmessagebox.question (self, page designer-uns
Aved Changes ", "Save unsaved changes?", qmessagebox.yes| qmessagebox.no) = = Qmessagebox.yes): Self.save () def position (self): point = Self.ma Pfromglobal (Qcursor.pos ()) if not Self.view.geometry (). Contains (point): Coord = Random.randint (36, 144 Point = Qpoint (coord, coord) else:if point = = Self.prevPoint:point = Qpoint (Self.addoffset, self.addoffset) Self.addoffset = 5 ELSE:SELF.ADDOFFSE t = 5 Self.prevpoint = point return Self.view.mapToScene (point) def addtext (self): D Ialog = Textitemdlg (Position=self.position (), Scene=self.scene, parent=self) dialog.e Xec_ () def addbox (self): Boxitem (Self.position (), Self.scene) def addpixmap (self): path = (qfi
Leinfo (self.filename). Path () if self.filename else "." Fname,filetype = Qfiledialog.getopenfilename (self, page designer-add pixmap, Path, "Pixmap Files (*.bmp *.jpg *.png *.xpm)") If not Fname:return Self.createpixmapitem (QPIXM AP (fname), Self.position ()) def createpixmapitem (self, pixmap, position, Matrix=qtransform ()): item = Graphi
Cspixmapitem (pixmap) item.setflags (qgraphicsitem.itemisselectable| qgraphicsitem.itemismovable) Item.setpos (position) item.settransform (matrix) Self.scene.clearSelec tion () Self.scene.addItem (item) item.setselected (True) global Dirty Dirty = True r
Eturn Item def selecteditem (self): items = Self.scene.selectedItems () If len (items) = 1:
Return items[0] Return to none def copy (self): item = Self.selecteditem () If Item is None:
Return Self.copiedItem.clear () Self.pasteoffset = 5 stream = Qdatastream (Self.copieditem, qiodevice.writeonly) self.writeitemtost
Ream (Stream, item) def cut (self): item = Self.selecteditem () The If item is None:return Self.copy () Self.scene.removeItem (item) del item def paste (self): if self.copiedItem.is Empty (): Return stream = Qdatastream (Self.copieditem, qiodevice.readonly) self.readitemfromstr EAM (Stream, Self.pasteoffset) Self.pasteoffset + + 5 def setalignment (self, Alignment): # Items are R
Eturned in arbitrary order items = Self.scene.selectedItems () If Len (items) <= 1:return
# Gather coordinate data leftxs, Rightxs, topys, Bottomys = [], [], [], [] for item in items: Rect = Item.sceneboundingrect () leftxs.append (Rect.x ()) Rightxs.append (Rect.x () + rect.width ()) Topys.apPend (Rect.y ()) Bottomys.append (Rect.y () + rect.height ()) # perform alignment if alignment = = Q T.alignleft:xalig