Before we develop a local application, we have to have a window to display the interface. Second, we also have to implement the redrawing mechanism, so that the game constantly refreshed, to achieve the purpose of dynamic. So the first stage of our engine development is to create windows and redraw the interface.
Here are the previous articles:
Python Game engine Development (i): Preface
The rendering mechanism of QT
In the previous chapter "Preface" We talked about this development using the PYQT, which is the Python version of Qt. Before we begin to implement the engine features, we need to know about QT First, here we understand the rendering mechanism.
In Qt, the class that the painting uses is called, as the QPainter
name implies, is a painter class bar. In this class, there are a lot of ways to manipulate the "painter", such as asking him to draw a circle, to measure the size of the text, Mr Painter certainly will not refuse.
When used QPainter
, it is necessary to give a painting device, which is similar to the painter's artboard. This painting equipment is one QWidget
, part class. This class also provides a number of methods, such as setting part size. In Qt, if there is only one QWidget
, then this QWidget
becomes the Window object.
Events in QT and signals and slots
QT events and JavaScript DOM events are a little different, not by registering an event type and the corresponding listener for the event callback, but QT directly in the class to write the listener, by overriding the listener method to execute their own code, that is, JS event is added to the call , and Qt is automatically added to the event by modifying the listener to execute the custom code. But Qt added the function of JS to add a kind of argument-signal and slot. This is the same as the Count of Monte Cristo Fairline betrayed the king of Ali the same paragraph-sent is the dagger detonated bombs blew up all the property and family, sent the ring is safe. Here the "dagger" is the signal, "detonate bombs" is the slot; "Send the Ring" is the signal, "safe" for the slot. You can also interpret the signal as the event name and the slot as a callback function.
The painting mentioned above needs to be QWidget
paintEvent
carried out in the middle.
Qapplication
Qapplication is the portal for the entire application. This class is a bit special, specifically where is it? Take a look at the following code:
app = QtGui.QApplication(sys.argv)# ...app.exec_()
In other words, if you want to use a series of functions in Qt, QApplication
after instantiating it, exec_
use these functions before invoking the method, that is, where the entry of the program is in the code # ...
. Also, QApplication
accept a parameter, which is the code sys.argv
, so you need to introduce the SYS module before using it.
Here, incidentally, some of the QT modules. Qt as a powerful engine, inevitably have a lot of modules, but we basically use only QtGui
, QtCore
QtWebKit
these modules. Development of the game, the QtGui
QtCore
two modules are enough.
Library base class
The basic part is roughly finished, begin encapsulation, the first package is the Stage
class. This class is basically to manage some of the global things, such as the size of the window, set the window refresh frequency, to the lowest level to add display objects and so on. But before we implement the stage, we have to create the lowest class in the library Object
:
class Object(object): 0 def __init__(self): 1 self.objectIndex = Object.latestObjectIndex
This class is used as the base class for all classes in a library, so that it is easy to extend functionality to all classes later. Then there is the constructor part of the stage class:
class stage (Object) : def __init__ : super (Stage, self). __init__ () self.parent = " root " self.width = 0 self.height = 0 self.speed = 0 self.app = none self.canvaswidget = none Self.canvas = None< /span> Self.timer = none self.childlist = [] Self.backgroundcolor = none
The
can see that the class contains many global properties. For example, width
and height
are used to get the height of the game interface, and backgroundcolor
is used to set the background.
Next is the Setcanvas
method, which is used to finish creating the painting device and Qpainter
and redraw the timer:
def _setcanvas (self, speed, title, width, height) : self.speed = Speed Self.width = width self.height = Height Self.canvas = Qtgui . Qpainter () Self.canvaswidget = Canvaswidget () self.canvasWidget.setWindowTitle (title) SELF.CANVASWIDG Et.setfixedsize (width, height) self.canvasWidget.show () Self.timer = Qtcore.qtimer () self.timer.setIn Terval (Speed) self.timer.start (); QtCore.QObject.connect (Self.timer, qtcore.signal ( "timeout ()" ), Self.canvaswidget, Qtcore.slot ( "update ()" ))
QT QTimer
is a timer class that invokes setInterval
methods to set the timing time and cycle the timings. start
method to turn on the timer. The method is then used to connect
connect the signal and slot, the signal is "timed out" and the slot is "Refresh window". In this way, we can use this signal slot device to achieve the function of the timed refresh interface.
In the code above, we have also saved the drawing class QPainter
, which calls the brush in a later code.
The above code also has a class, derived from the class, CanvasWidget
in which QWidget
we will also add other functions, such as rewriting the Paint event listener, keyboard event listener, and so on. The constructor code is as follows:
class CanvasWidget(QtGui.QWidget): def __init__(self): super(CanvasWidget, self).__init__()
Of course, QT provides us with more than just this kind of basic parts, as QWidget
well as input boxes, buttons, Windows and other advanced components, but we temporarily do not use these parts, let alone qt in the absence of other widgets, will default to the first QWidget
set as a Window object, so here is CanvasWidget
inherited from QWidget
, when instantiated, is the Window object.
The above setWindowTitle
and setFixedSize
methods are used to set the window title, window fixed size. Then use show
the method to display the part.
Because there can only be one object in the whole game, in Stage
order to facilitate the use of the global public, we instantiate this class directly in the library, as the only stage object:
stage = Stage()
In the above setCanvas
method, we use the signal slot to complete the interface refresh, then exactly how to refresh it? When our timer is timed to the specified time, the slot of the part is called, and in update
this slot it is called into paintEvent
, as we mentioned in "events in QT and Signals and slots", this event is QWidget
already written in, we just need CanvasWidget
to You can override this function in:
def paintEvent(self, event): stage._onShow()
Call into Stage
the method of the object _onShow
:
def _onshow (self) : self.canvas.begin (self.canvaswidget) if self.backgroundcolor is not none : Self.canvas.fillRect (
0 ,
0 , Self.width, Self.height, GetColor ( Self.backgroundcolor))
else : Self.canvas.eraseRect (
0 ,
0 , Self.width, Self.height) self._showdisplaylist (self.childlist ) self.canvas.end ()
In this function, we first use QPainter
the begin
method to bind the painting device. The erase interface is then re-painted by means of the _showDisplayList
method, and finally the painting is finished. It is noteworthy that the _showDisplayList
method, which iterates through the display list, will iterate over the object to be redrawn:
def _showDisplayList(self, childList): forin childList: if"_show"and"__call__"): o._show(self.canvas)
We can finish drawing the object by invoking the method of displaying the object _show
. In subsequent development, we just need to add a method to an object and _show
then join the display list to redraw the object. If you add the function of the picture in the picture, _show
then get the image class, add the function of painting text, it becomes the text class.
In the _onShow
method we also use getColor
this global function, used to convert the color name string or 16 binary value into QColor
, after all, QT this illiterate, recognize the color is only recognized QColor
:
def getColor(color): if isinstance(color, QtGui.QColor): return color elifnot color: return QtCore.Qt.transparent else: colorObj = QtGui.QColor() colorObj.setNamedColor(color) return colorObj
Because the Stage
class is used as the lowest-level display list, the Join addChild
method is removeChild
used to complete the addition and deletion of the display object:
def addChild(self, Child): ifChild is not None: Child.parent = self self.childList.append (child)Else:RaiseValueError ("parameter ' child ' must is a display object.") def removechild(self, Child): ifChild is not None: Self.childList.remove (child) Child.parent =None Else:RaiseValueError ("parameter ' child ' must is a display object.")
Finally, add the init
global function to initialize the interface:
def init(speed, title, width, height, callback): stage.app = QtGui.QApplication(sys.argv) stage._setCanvas(speed, title, width, height) ifnot"__call__"): raise ValueError("parameter ‘callback‘ must be a function.") callback() stage.app.exec_()
One of the QApplication
above has been described in detail.
Call the init
function and pass in the corresponding parameter to see the empty window.
All the code in this article:
class object(object):Latestobjectindex =0 def __init__(self):Object.latestobjectindex + =1Self.objectindex = Object.latestobjectindex class canvaswidget(qtgui.qwidget): def __init__(self):Super (Canvaswidget, self). __init__ () self.setmousetracking (True) def paintevent(self, event):Stage._onshow () class Stage(Object): def __init__(self):Super (Stage, self). __init__ () Self.parent ="Root"Self.width =0Self.height =0Self.speed =0Self.app =NoneSelf.canvaswidget =NoneSelf.canvas =NoneSelf.timer =NoneSelf.childlist = [] Self.backgroundcolor =None def _setcanvas(self, speed, title, width, height):Self.speed = Speed Self.width = width self.height = Height Self.canvas = qtgui.qpainter () Self . Canvaswidget = Canvaswidget () self.canvasWidget.setWindowTitle (title) self.canvasWidget.setFixedSize (width, Height) self.canvasWidget.show () Self.timer = Qtcore.qtimer () self.timer.setInterval (speed) s Elf.timer.start (); QtCore.QObject.connect (Self.timer, Qtcore.signal ("timeout ()"), Self.canvaswidget, Qtcore.slot ("Update ()")) def _onshow(self):Self.canvas.begin (Self.canvaswidget)ifSelf.backgroundcolor is not None: Self.canvas.fillRect (0,0, Self.width, Self.height, GetColor (Self.backgroundcolor))Else: Self.canvas.eraseRect (0,0, Self.width, Self.height) self._showdisplaylist (self.childlist) self.canvas.end () def _showdisplaylist(self, childlist): forOinchChildlist:ifHasattr (O,"_show") andHasattr (O._show,"__call__"): O._show (Self.canvas) def addChild(self, Child): ifChild is not None: Child.parent = self self.childList.append (child)Else:RaiseValueError ("parameter ' child ' must is a display object.") def removechild(self, Child): ifChild is not None: Self.childList.remove (child) Child.parent =None Else:RaiseValueError ("parameter ' child ' must is a display object.") def init(speed, title, width, height, callback):Stage.app = Qtgui.qapplication (SYS.ARGV) Stage._setcanvas (speed, title, width, height)if notHasattr (Callback,"__call__"):RaiseValueError ("parameter ' callback ' must be a function.") Callback () Stage.app.exec_ () def getColor(color): ifIsinstance (color, Qtgui.qcolor):returnColorelif notColorreturnQtCore.Qt.transparentElse: Colorobj = Qtgui.qcolor () colorobj.setnamedcolor (color)returnColorobj
preview: Next we implement the display picture.
You are welcome to follow my blog
Reprint Please specify source: Yorhom's Game box
Http://blog.csdn.net/yorhomwang
Python Game Engine Development (II): Creating a window and redrawing the interface