Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of graphic View Framework in PyQt5

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article will explain in detail the example analysis of the graphic view framework in PyQt5. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.

1.QGraphicsItem element class

Elements can be text, pictures, regular geometry, or any custom graphics. This class already provides some standard elements, such as:

Line entity QGraphicsLineItem

Rectangular entity QGraphicsRectItem

Elliptic primitive QGraphicsEllipseItem

Picture element QGraphicsPixmapItem

Text element QGraphicsTextItem

Path entity QGraphicsPathItem

Presumably, you can also know what these elements are used for by their names, and we demonstrate how to use them through the following code:

Import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtGui import QPixmap, QColor, QPainterPathfrom PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsLineItem, QGraphicsRectItem, QGraphicsEllipseItem,\ QGraphicsPixmapItem, QGraphicsTextItem, QGraphicsPathItem, QGraphicsScene, QGraphicsViewclass Demo (QGraphicsView): def _ init__ (self): super (Demo, self). _ init__ () # 1 self.resize # 2 self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,300,300) # 3 self.line = QGraphicsLineItem () self.line.setLine (100,10,200,10) # self.line.setLine (QLineF (100,10,200,10)) # 4 self.rect = QGraphicsRectItem () self.rect.setRect (100,30,100 30) # self.rect.setRect (QRectF (100,30,100,30)) # 5 self.ellipse = QGraphicsEllipseItem () self.ellipse.setRect (100,80,100,20) # self.ellipse.setRect (QRectF (100,80,100,20) # 6 self.pic = QGraphicsPixmapItem () self.pic.setPixmap (QPixmap ('pic.png'). Scaled (60) 60) self.pic.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.pic.setOffset (100,120) # self.pic.setOffset (QPointF (100,120)) # 7 self.text1 = QGraphicsTextItem () self.text1.setPlainText ('Hello PyQt5') self.text1.setDefaultTextColor (QColor (66,222,88)) self.text1.setPos Self.text2 = QGraphicsTextItem () self.text2.setPlainText ('Hello World') self.text2.setTextInteractionFlags (Qt.TextEditorInteraction) self.text2.setPos (100,200) self.text3 = QGraphicsTextItem () self.text3.setHtml (' Baidu') self.text3.setOpenExternalLinks (True) self.text3.setTextInteractionFlags (Qt.TextBrowserInteraction) self.text3.setPos 8 self.path = QGraphicsPathItem () self.tri_path = QPainterPath () self.tri_path.moveTo (100250) self.tri_path.lineTo (130,290) self.tri_path.lineTo (100,290) self.tri_path.lineTo Self.tri_path.closeSubpath () self.path.setPath (self.tri_path) # 9 self.scene.addItem (self.line) self.scene.addItem (self.rect) self.scene.addItem (self.ellipse) self.scene.addItem (self.pic) self.scene.addItem (self.text1) self.scene.addItem (self.text2) Self.scene.addItem (self.text3) self.scene.addItem (self.path) # 10 self.setScene (self.scene) if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

1. This class directly inherits QGraphicsView, so the window is the view and the size is 300x300

two。 Instantiate a QGraphicsScene scene and call the setSceneRect (x, y, w, h) method to set the origin and size of the scene coordinates. We know from the code that the coordinate origin is (0,0), and then all the elements added to the scene will be positioned according to that coordinate (the author will explain more about the coordinates in section 34.4). The size of the scene is 300x300, the same size as the view

3. Instantiate a QGraphicsLineItem line entity and call the setLine () method to set the coordinates at both ends of the line. This method can pass in either four values directly or a QLineF object. It is very clear in the document:

4-5. Similar to line entities, rectangular and elliptical entities are instantiated respectively, and the corresponding methods are called to set the position and size.

6. Instantiate a picture element, and call the setPixmap () method to set the picture, the QPixmap object has a scaled () method that sets the size of the picture (of course, we can also use QGraphicsItem's setScale () method to set the size), and then we set the Flag property of the element so that it can be selected and moved, which is a common method for all elements. Finally, the setOffset () method is called to set the offset of the picture from the origin of the scene coordinates.

7. Here, three text elements are instantiated, displaying plain green text, editable text, and hyperlinked text (HTML). The setDefaultColor () method can be used to set the color of the text, and setPos () can be used to set the position of the text element relative to the scene coordinate origin (this method is common to all elements, and of course we can also use it on other types of elements).

SetTextInteractionFlags () is used to set text properties, where the Qt.TextEditorInteraction parameter is represented as an editable attribute (equivalent to editing text on QTextEdit), and the final Qt.TextBrowserInteraction indicates that the text is used for browsing (equivalent to text on QTextBrowser). For more attributes, you can search for Qt::TextInteractionFlags in the documentation.

Of course, if we want the hyperlink text to be opened, we also need to use the setOpenExternalLinks () method, passing in a True parameter.

8. Path elements can be used to display graphics of any shape, and the setPath () method needs to pass in a QPainterPath object that we use for drawing. The moveTo () method means to move the brush to the appropriate position, lineTo () means to draw a straight line, and the closeSubpath () method indicates the end of the current painting (see the documentation for more methods about QPaintPath objects). Here we draw a right triangle.

9. Call the addItem () method of the scene to add all the elements

10. Call the setScene () method to center the scene in the view.

The screenshot of the operation is as follows:

Pictures can be selected and moved:

Hello World text can be edited:

QGraphicsItem also supports the following features:

Mouse down, move, release and double click events, as well as mouse hover events, wheel events, and right-click menu events

Keyboard input event

Drag and drop event

Grouping

Collision detection

Implementing the event function is very simple, so I won't go into details here, but let's focus on how it is passed in the graphical view framework. Take a look at the following code:

Import sysfrom PyQt5.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsViewclass CustomItem (QGraphicsRectItem): def _ _ init__ (self): super (CustomItem, self). _ init__ () self.setRect (100,30,100,30) def mousePressEvent (self, event): print ('event from QGraphicsItem') super (). MousePressEvent (event) class CustomScene (QGraphicsScene): def _ init__ (self): super (CustomScene) Self). _ init__ () self.setSceneRect (0,0,300,300) def mousePressEvent (self, event): print ('event from QGraphicsScene') super () .mousePressEvent (event) class CustomView (QGraphicsView): def _ init__ (self): super (CustomView, self). _ init__ () self.resize (300,300) def mousePressEvent (self) Event): print ('event from QGraphicsView') super (). MousePressEvent (event) if _ _ name__ =' _ _ main__': app = QApplication (sys.argv) view = CustomView () scene = CustomScene () item = CustomItem () scene.addItem (item) view.setScene (scene) view.show () sys.exit (app.exec_ ())

Elements, scenes and views all have their own event functions. We inherit QGraphicsRectItem, QGraphicsScene and QGraphicsView respectively and re-implement their respective mousePressEvent () event functions, in which we all print a sentence to let the user know which function has been executed.

The screenshot of the operation is as follows:

After clicking in the rectangle, we find that the console enters the following information:

Thus, the delivery order of events is view-> scene-> element. It is important to note that if we re-implement the event function, we must call the corresponding parent event function, otherwise the event will not be passed smoothly. If I delete the line of super (). MousePressEvent (event) under the event function in the CustomView class, the console will only output "event from QGraphicsView":

You can add another element to an element (one element can be the parent of another element), so what is the sequence of events between elements? Take a look at the following code:

Import sysfrom PyQt5.QtWidgets import QApplication, QGraphicsRectItem, QGraphicsScene, QGraphicsViewclass CustomItem (QGraphicsRectItem): def _ _ init__ (self, num): super (CustomItem, self). _ _ init__ () self.setRect (100,30,100,30) self.num = num def mousePressEvent (self Event): print ('event from QGraphicsItem {}' .format (self.num)) super (). MousePressEvent (event) if _ name__ ='_ main__': app = QApplication (sys.argv) view = QGraphicsView () scene = QGraphicsScene () item1 = CustomItem (1) item2 = CustomItem (2) item2.setParentItem (item1) scene.addItem (item1) view.setScene (scene) view.show Sys.exit (app.exec_ ())

Because two identical rectangle sources are instantiated, in order to distinguish, we add a num parameter to the initialization function of CustomItem, and then print out the number passed in when instantiation in the event function.

Call the setParentItem () method to make item1 the parent of item2, and then add item1 to the scene (item2 is naturally added).

The screenshot of the operation is as follows:

Click in the rectangle and the console prints as follows:

Thus, the event is passed from the child element to the parent entity. By the same token, if you do not add super (). MousePressEvent (event), then the event will stop passing and only "event from QGraphicsItem2" will be displayed:

Please be sure to understand the order in which events are delivered so that you can make better use of the graphical view framework.

The so-called grouping is to classify the elements, and the elements that are grouped together will act together (select, move, copy, etc.). Let's demonstrate it with the following code:

Import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtGui import QPen, QBrushfrom PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsScene,\ QGraphicsView, QGraphicsItemGroupclass Demo (QGraphicsView): def _ init__ (self): super (Demo, self). _ _ init__ () self.resize (300,300) self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,300) Self.rect1 = QGraphicsRectItem () self.rect2 = QGraphicsRectItem () self.ellipse1 = QGraphicsEllipseItem () self.ellipse2 = QGraphicsEllipseItem () self.rect1.setRect (100,30,100,30) self.rect2.setRect (100,80,100,30) self.ellipse1.setRect (100,140,100,20) self.ellipse2.setRect (100,180,100) 50) # 2 pen1 = QPen (Qt.SolidLine) pen1.setColor (Qt.blue) pen1.setWidth (3) pen2 = QPen (Qt.DashLine) pen2.setColor (Qt.red) pen2.setWidth (2) brush2 = QBrush (Qt.SolidPattern) brush2.setColor (Qt.blue) brush3 = QBrush (Qt.SolidPattern) brush3.setColor (Qt .red) self.rect1.setPen (pen1) self.rect1.setBrush (brush2) self.rect2.setPen (pen2) self.rect2.setBrush (brush3) self.ellipse1.setPen (pen1) self.ellipse1.setBrush (brush2) self.ellipse2.setPen (pen2) self.ellipse2.setBrush (brush3) # 3 self.group1 = QGraphicsItemGroup () self Group2 = QGraphicsItemGroup () self.group1.addToGroup (self.rect1) self.group1.addToGroup (self.ellipse1) self.group2.addToGroup (self.rect2) self.group2.addToGroup (self.ellipse2) self.group1.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.group2.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) print (self.group1.boundingRect ()) print (self. Group2.boundingRect () # 4 self.scene.addItem (self.group1) self.scene.addItem (self.group2) self.setScene (self.scene) if _ _ name__ ='_ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

1. Instantiate four entities, two rectangles and two ellipses, and call the setRect () method to set the coordinates and size

two。 Instantiate two brushes and two brushes for styling elements

3. Instantiate two QGraphicsGroup grouping objects and add both rectangles and ellipses. Rect1 and ellipse1 are in group1, while rect2 and ellipse2 are in group2. Then call the setFlags () method to set the properties so that the grouping can be selected and moved. The boundRect () method returns a QRectF value that shows the boundary location and size of the grouping

4. Add grouping to the scene.

The screenshot of the operation is as follows:

Blue rectangles and ellipses are a group that can be selected and moved at the same time, and red ones are the same. The black border is the boundary, and its location and size can be obtained by the boundRect () method. Through the screenshot below, we can find that the location and size of the boundary of the QGraphicsItemGroup are determined by the elements in it as a whole:

Collision detection is very useful in the game, for example, in the aircraft war game, if the bullets do not do collision detection with the enemy aircraft, then the enemy aircraft will not be eliminated, the reward will not be increased, and the game will not be interesting. Let's use the following example to show you how to perform collision detection on elements:

There is a rectangular element and an ellipse element on the interface, both of which can be selected and moved. We'll run a collision test on the two. Before that, let's take a look at the difference between the boundingRect () boundary and the shape () shape. Look at the elliptical entity below:

When the element is selected, the dashed part shows the boundary of the element, and the shape refers to the element itself, that is, the solid black line. Collision detection can be based on the boundary or the shape. If we take the boundary as the range in the code, the collision detection will be triggered as soon as the dotted line of the ellipse meets the rectangular element; if the shape is taken as the range, the collision detection will be triggered only if the solid black line of the ellipse meets the rectangle.

Here are several specific detection methods:

Take a look at the code example below:

Import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsScene,\ QGraphicsViewclass Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ init__ () self.resize (300,300) self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,300) Self.rect = QGraphicsRectItem () self.ellipse = QGraphicsEllipseItem () self.rect.setRect (120,30,50,30) self.ellipse.setRect (100,180,100) 50) self.rect.setFlags (QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) self.ellipse.setFlags (QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) self.scene.addItem (self.rect) self.scene.addItem (self.ellipse) self.setScene (self.scene) def mouseMoveEvent (self, event): if self.ellipse.collidesWithItem (self.rect Qt.IntersectsItemBoundingRect): print (self.ellipse.collidingItems (Qt.IntersectsItemShape)) super (). MouseMoveEvent (event) if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

I'm sure you all understand the code in the initialization function, so instead of talking about it here, let's focus on the mouseMoveEvent () event function.

We call the collidesWithItem () method of the elliptical entity to specify the other elements with which to perform collision detection and the detection method. The other elements refer to rectangular elements, and we can see that this is bounded by the boundary of the ellipse, and detection is triggered as long as the two elements intersect. If the collision condition is true, then collidesWithItem () returns a True, so the if condition judgment is also true.

After specifying the detection method, the collidingItems () method can return all other elements that meet the collision criteria, and the return type is a list. The detection method here is based on the shape, and there is also an intersection.

The meaning of the mouseMoveEvent () event function is: when the boundary of the ellipse touches the rectangle, then the if condition judgment is established, but at this time the print is only an empty list, because the ellipse itself (black solid line) has not yet touched the rectangle. However, when touched, the console will output a list of rectangular elements.

Please call the collidesWithItem () and collidingItems () methods of rectangular elements to try and see what the difference is. That is, modify the mouseMoveEvent () event function as follows:

Def mouseMoveEvent (self, event): if self.rect.collidesWithItem (self.ellipse, Qt.IntersectsItemBoundingRect): print (self.rect.collidingItems (Qt.IntersectsItemShape)) super (). MouseMoveEvent (event)

For performance reasons, QGraphicsItem does not inherit from QObject, so it does not use signal and slot mechanisms, and we cannot animate it. However, we can customize a class and have it inherit from QGraphicsObject. Take a look at the following solution:

Import sysfrom PyQt5.QtCore import QPropertyAnimation, QPointF, QRectF, pyqtSignalfrom PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QGraphicsObjectclass CustomRect (QGraphicsObject): # 1 my_signal = pyqtSignal () def _ init__ (self): super (CustomRect, self). _ init__ () # 2 def boundingRect (self): return QRectF (0,0,100,30) # 3 def paint (self, painter, styles) Widget=None): painter.drawRect (self.boundingRect ()) class Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ _ init__ () self.resize Self.rect = CustomRect () self.rect.my_signal.connect (lambda: print ('signal and slot')) self.rect.my_signal.emit () self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,300,300) self.scene.addItem (self.rect) self.setScene (self.scene) # 5 self.animation = QPropertyAnimation (self.rect) ) self.animation.setDuration (3000) self.animation.setStartValue (QPointF (100,30)) self.animation.setEndValue (QPointF (100,200)) self.animation.setLoopCount (- 1) self.animation.start () if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

1. Customize a signal

2-3. If we inherit QGraphicsObject, we'd better reimplement the boundingRect () and paint () methods. In boundingRect () we return a value of type QRectF to determine the default location and size of the CustomRect. Call the drawRect () method in paint () to draw the rectangle onto the interface.

4. Connect the custom signal with the slot function, and print the "signal and slot" string in the slot function. Then call the emit () method of the signal to transmit the signal, and the slot function will start.

5. Add the QPropertyAnimation attribute animation, move the rectangle from (100,30) to (100,200), the time is 3 seconds, the animation loop infinitely.

The running screenshot is as follows, and the rectangular element moves slowly from top to bottom:

Console print content:

2.QGraphicsScene scene class

In the previous section, when we want to add elements to the scene, we first instantiate the elements, and then call the scene's addItem () method to add them. However, the scene also provides the following ways to quickly add elements:

Of course, the scene also provides many ways to manage elements. Let's learn from the following code:

Import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtGui import QPixmap, QTransformfrom PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsScene, QGraphicsViewclass Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ _ init__ () self.resize (300,300) self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,300,300) # 1 self.rect = self.scene.addRect (100,30,100 30) self.ellipse = self.scene.addEllipse (100,80,50,40) self.pic = self.scene.addPixmap (QPixmap ('pic.png'). Scaled (60,60) self.pic.setOffset Self.rect.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsFocusable) self.ellipse.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsFocusable) self.pic.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsFocusable) self.setScene (self.scene) # 2 print (self.scene.items ()) print (self.scene.items (order=Qt.AscendingOrder)) Print (self.scene.itemsBoundingRect ()) print (self.scene.itemAt 40, QTransform () # 3 self.scene.focusItemChanged.connect (self.my_slot) def my_slot (self, new_item, old_item): print ('new item: {}\ nold item: {}' .format (new_item, old_item)) # 4 def mouseMoveEvent (self, event): print (self.scene.collidingItems (self.ellipse) Qt.IntersectsItemShape)) super () .mouseMoveEvent (event) # 5 also needs to modify def mouseDoubleClickEvent (self, event): item = self.scene.itemAt (event.pos () QTransform () self.scene.removeItem (item) super () .mouseDoubleClickEvent (event) if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

1. Directly call the scene's addRect (), addEllipse (), and addPixmap () methods to add elements. Here we need to know a point of knowledge: the first element is added below the element (Z axis direction), you can run the code and then move the element, and then you will find that the picture element in the program is at the top, the ellipse is second, and the rectangle is at the bottom. However, we can change the up and down position by calling the setZValue () method of the element (refer to the documentation, which is not explained in detail here).

Next, set the Flag property of the element. The extra ItemIsFocusable here means that the element can be focused (not focused by default), which is related to the foucsItemChanged signal to be discussed in the third dot below.

two。 Call the items () method to return all the elements in the scene with a list of value types. By default, the returned elements are in descending order (Qt.DescendingOrder), that is, arranged from top to bottom (QPixmapItem, QEllipseItem, QRectItem). You can modify the value of the order parameter so that the elements returned in the list are arranged in ascending order.

ItemsBoundingRect () returns the overall boundary of all elements.

ItemAt () can return the element in the specified location. If there are two overlapping elements in this position, then return the top element. The QTransform () passed in is related to the Flag property ItemIgnoresTransformations of the element. Since this property is not set here, we can pass it directly into QTransform () (not detailed here, otherwise it may be confusing, and you can simply remember it first, and then study it in depth).

3. The scene has a focusChangedItem signal that is emitted when we select a different element, provided that the element has the ItemIsFocusable property set. The signal can pass two values, the first is the newly selected element, and the second is the previously selected element

4. Call collidingItems () of the scene to print out all other elements that collide with the target element under the specified collision trigger condition.

5. By double-clicking on the element, we can call the removeItem () method to delete it. Note that it is actually inaccurate to pass event.pos () directly to itemAt (), because event.pos () is actually the coordinates of the mouse on the view rather than the coordinates on the scene. You can enlarge the window, and then double-click, you will find that the element will not disappear, this is because the view size is no longer the same as the scene size, and the coordinates have changed. For specific solutions, please see section 34.4.

The screenshot of the operation is as follows:

Console print content:

Double-click an element to delete it:

We can also add simple or complex controls such as QLabel, QLineEdit, QPushButton, QTableWidget, etc., to the scene, or even add a main window directly. Next, we will learn more about it by completing the following interface (that is, the interface example in Chapter 3 layout management):

The code is as follows:

Import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QGraphicsWidget, QGraphicsGridLayout,\ QGraphicsLinearLayout, QLabel, QLineEdit, QPushButtonclass Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ init__ () self.resize 1 self.user_label = QLabel ('Username:') self.pwd_label = QLabel (' Password:') self.user_line = QLineEdit () self.pwd_line = QLineEdit () self.login_btn = QPushButton ('Log in') self.signin_btn = QPushButton (' Sign in') # 2 self.scene = QGraphicsScene () Self.user_label_proxy = self.scene.addWidget (self.user_label) self.pwd_label_proxy = self.scene.addWidget (self.pwd_label) self.user_line_proxy = self.scene.addWidget (self.user_line) self.pwd_line_proxy = self.scene.addWidget (self.pwd_line) self.login_btn_proxy = self.scene.addWidget (self.login_btn) Self.signin_btn_proxy = self.scene.addWidget (self.signin_btn) print (type (self.user_label_proxy)) # 3 self.g_layout = QGraphicsGridLayout () self.l_h_layout = QGraphicsLinearLayout () self.l_v_layout = QGraphicsLinearLayout (Qt.Vertical) self.g_layout.addItem (self.user_label_proxy 0,0,1,1) self.g_layout.addItem (self.user_line_proxy, 0,1,1) self.g_layout.addItem (self.pwd_label_proxy, 1,0,1,1) self.g_layout.addItem (self.pwd_line_proxy, 1,1,1) 1) self.l_h_layout.addItem (self.login_btn_proxy) self.l_h_layout.addItem (self.signin_btn_proxy) self.l_v_layout.addItem (self.g_layout) self.l_v_layout.addItem (self.l_h_layout) # 4 self.widget = QGraphicsWidget () self.widget.setLayout (self.l_v_ Layout) # 5 self.scene.addItem (self.widget) self.setScene (self.scene) if _ _ name__ = ='_ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

1. Instantiate the required control, because the parent class is not QGraphicsView, so do not add self

two。 Instantiate a scene object and then call the addWidget () method to add the control. The value returned by the addWidget () method is actually a QGraphicsProxyWidget proxy object, and the control is embedded in the proxy layer provided by the object. The state of user_label_proxy is consistent with that of user_label. If we disable or hide user_label_proxy, then the corresponding user_label will also be disabled or hidden, so we can manipulate the control by controlling the proxy object in the scene (but signals and slots are still directly applied to the control, which is not provided by the proxy object).

3. For layout, note that you are using the layout manager in the graphical view framework: QGraphicsGridLayout grid layout and QGraphicsLinearLayout linear layout (a combination of horizontal and vertical layouts). But the usage is pretty much the same, except that the method called is addItem () instead of addWidget () or addLayout (). The linear layout is horizontal by default. We can input Qt.Vertical for vertical layout when instantiating. (there is also an anchor layout QGraphicsAnchorLayout in the graphic view, which is no longer explained here. I believe you can also read the document.)

4. Instantiate a QGraphicsWidget, which is similar to QWidget, except that on the side of the graphical view framework, call the setLayout () method to set the overall layout

5. Add the QGraphicsWidget object to the scene, and the controls embedded in QGraphicsProxyWidget will naturally be on the scene, and finally the scene will be displayed in the view.

3.QGraphicsView View Class

The view is actually a scrolling area, and if the view is smaller than the scene size, the window will display a scroll bar so that the user can see the entire scene (on Linux and Windows systems, the scroll bar will also be displayed if the view is the same size as the scene). In the following code, the author makes the scene larger than the view:

Import sysfrom PyQt5.QtCore import QRectFfrom PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsViewclass Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ init__ () self.resize (300,300) self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,500,500) self.scene.addEllipse (QRectF (200,200,50) 50) self.setScene (self.scene) if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

The view size is 300x300 and the scene size is 500x500.

The screenshot of the operation is as follows:

MacOS

Linux (Ubuntu)

Windows

Now that the elements have been added and the scene has been set up, we can usually call some methods of the view to make some changes to the elements, such as zooming in, zooming out, and rotating. Take a look at the following code:

Import sysfrom PyQt5.QtCore import Qt, QRectFfrom PyQt5.QtGui import QColor, QBrushfrom PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsScene, QGraphicsViewclass Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ init__ () self.resize (300,300) self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,500,500) self.ellipse = self.scene.addEllipse (QRectF (200,200,50,50) Brush=QBrush (QColor (Qt.blue)) self.rect = self.scene.addRect (QRectF (300,300,50,50), brush=QBrush (QColor (Qt.red)) self.ellipse.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.rect.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.setScene (self.scene) self.press_x = None # 1 def wheelEvent (self, event): if event.angleDelta (). Y ()

< 0: self.scale(0.9, 0.9) else: self.scale(1.1, 1.1) # super().wheelEvent(event) # 2 def mousePressEvent(self, event): self.press_x = event.x() # super().mousePressEvent(event) def mouseMoveEvent(self, event): if event.x() >

Self.press_x: self.rotate (10) else: self.rotate (- 10) # super (). MouseMoveEvent (event) if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

1. In the mouse wheel event, call the scale () method to zoom in and out of the view. There is no need to call the event function of the parent class, because we do not need to pass events to the scene and elements

two。 Re-implement the mouse press and move event function, first obtain the coordinates of the mouse down, and then determine whether the mouse moves to the left or right. If to the right, the view rotates 10 degrees clockwise, otherwise it rotates 10 degrees counterclockwise.

The screenshot of the operation is as follows:

Zoom in and out

Rotation

Of course, views also provide many methods, for example, you can also use items () and itemAt () to get elements, you can also set the view background, view cache mode, mouse drag mode, and so on. You can refer to it as needed (there is too much talk here about fear of chaos).

4. Coordinate system of graphic view

(updated) the graphical view is based on the Cartesian coordinate system, the view, the scene and the primitive coordinate system are all the same-the upper left corner is the origin, the right is the x positive axis, and the downward is the y positive axis.

The graphical view provides a function for converting between three coordinate systems, and a conversion function between elements:

OK, now let's talk about the problem in section 34.2, the code is as follows:

Import sysfrom PyQt5.QtGui import QPixmap, QTransformfrom PyQt5.QtWidgets import QApplication, QGraphicsItem, QGraphicsScene, QGraphicsViewclass Demo (QGraphicsView): def _ _ init__ (self): super (Demo, self). _ init__ () self.resize (600,600) self.scene = QGraphicsScene () self.scene.setSceneRect (0,0,300,300) self.rect = self.scene.addRect (100,30,100) 30) self.ellipse = self.scene.addEllipse (100,80,50,40) self.pic = self.scene.addPixmap (QPixmap ('pic.png'). Scaled (60,60) self.pic.setOffset QGraphicsItem.ItemIsMovable) self.ellipse.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.pic.setFlags (QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.setScene (self.scene) def mouseDoubleClickEvent (self, event): item = self.scene.itemAt (event.pos () QTransform () self.scene.removeItem (item) super () .mouseDoubleClickEvent (event) if _ _ name__ ='_ _ main__': app = QApplication (sys.argv) demo = Demo () demo.show () sys.exit (app.exec_ ())

In the above program, the view size is 600x600, while the scene size is only 300x300. Running the program at this time, we can't delete the element if we double-click, because the event.pos () we get is the coordinates on the view, but self.scene.itemAt () needs the scene coordinates. The itemAt () method that passes the view coordinates to the scene won't get any elements, so we should convert it!

Modify the mouseDoubleClickEvent () event function as follows:

Def mouseDoubleClickEvent (self, event): point = self.mapToScene (event.pos ()) item = self.scene.itemAt (point, QTransform ()) self.scene.removeItem (item) super () .mouseDoubleClickEvent (event)

Call the view's mapToScene () method to convert the view coordinates to scene coordinates so that the elements can be found and deleted naturally.

The screenshot of the operation is as follows, and the ellipse is deleted:

5. Summary

1. The transmission order of events is view-> scene-> element. If it is passed between the parent and child classes of the element, the transfer order is from the child class to the parent class.

two。 The scope of collision detection can be divided into boundary and shape, and we need to understand the difference between them.

3. To add signal and slot mechanisms and animation to QGraphicsItem, customize a class that inherits from QGraphicsObject

4. To add QLabel, QLineEdit, QPushButton and other controls to the scene, we need to use QGraphicsProxyWidget

5. Views, scenes, and elements all have their own coordinate systems, so pay attention to using coordinate conversion functions for conversion.

6. There are too many knowledge points in the graphic view framework, the purpose of the author to write this chapter is to introduce you as far as possible, individual places may not explain in detail, please understand. For more details, you can search Qt Assistant for "Graphics View Framework" for more information.

This is the end of this article on "sample Analysis of graphical View Framework in PyQt5". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, please share it out for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report