我正在开发游戏,用qml和pyqt编写,但应分为两个窗口(Launcher +游戏)。在这两个qml文件之间切换的正确方法是什么?我不想使用QmlLoader,因为它没有调整窗口的大小,它需要很多信号!我也尝试了这个变种:
view.engine().clearComponentCache()
view.setSource(source())
但它没有用(qml窗口停止工作...... - 经典的Windows错误,但在pycharm控制台中没有写错误)
我的代码如下所示:
from PyQt5.QtCore import pyqtProperty, QRectF, QUrl, QObject, pyqtSignal, pyqtSlot, QVariant
from PyQt5.QtGui import QColor, QGuiApplication, QPainter, QPen
from PyQt5.QtQml import qmlRegisterType
from PyQt5.QtQuick import QQuickItem, QQuickPaintedItem, QQuickView
from PyQt5 import QtNetwork as QN
from PyQt5 import QtCore as QC
from multiprocessing import Process
import server as S
import client as C
from time import time, sleep
class Launcher(QQuickItem):
PORTS = (9998, 9999)
PORT = 9999
SIZEOF_UINT32 = 4
changeUI = pyqtSignal()
changeName= pyqtSignal(int, str)
connection= pyqtSignal(int, bool)
connected= pyqtSignal(QVariant)
@pyqtSlot(name="startGame")
def start_game(self):
#app.exit()
startGame()
print ("startGame")
@pyqtProperty(str)
def name(self):
print ("return name")
return self._name
@name.setter
def name(self, n):
print ("set name")
self._name= n
@pyqtSlot(name= "terminate")
def terminate_server(self):
if not self.server: return
self.server.terminate() #Bye
self.server.join()
#self.bstopServer.setEnabled(False)
#self.bserver.setEnabled(True)
self.server = None
@pyqtSlot()
def _quit(self):
if self.server:
self.server.terminate() #Bye
self.server.join()
app.exit()
@pyqtSlot()
def back(self):
self.client.disconnect()
def __init__(self, parent=None):
super(Launcher, self).__init__(parent)
self.socket= QN.QTcpSocket() #Yeah, the game will be over internet
self.server = None
self.client = None #client is a QObject
self._turnedOn = False
self._players = 1
self._name = "YourName"
class Game(QQuickItem):
def __init__(self, parent= None):
super(Game, self).__init__(parent)
self.client = True #I should get the client from the launcher, but I don´t know how
def startGame():
view.engine().clearComponentCache()
view.setResizeMode(QQuickView.SizeViewToRootObject)
view.showFullScreen()
view.setSource(
QUrl.fromLocalFile(
os.path.join(os.path.dirname(__file__),'Game.qml')))
view.show()
#app.exec_()
def startLauncher():
view.engine().clearComponentCache()
view.setResizeMode(QQuickView.SizeViewToRootObject)
view.setSource(
QUrl.fromLocalFile(
os.path.join(os.path.dirname(__file__),'Launcher.qml')))
view.show()
app.exec_()
if __name__ == '__main__':
import os
import sys
app = QGuiApplication(sys.argv)
qmlRegisterType(Launcher, "ParanoiaLauncher", 1, 0, "App")
qmlRegisterType(Game, "ParanoiaGame", 1, 0, "App")
view = QQuickView()
startLauncher()
正如你可能看到的,我的结构有点混乱,因为我第一次做这种切换行为,所以我真的不知道,应该怎么做才对...欢迎每一条建议! :)
答案 0 :(得分:2)
我不得不同时遇到同样的问题。而是一遍又一遍地使用相同的QQuickView
加载相同的组件,我在QML中创建了一个组件作为内容容器,并且我将所需的组件加载为它的子组件。每次设置新组件时,我们都会销毁当前组件并将新组件再次设置为子组件。
// ContentFrame.qml
Item{
width: 800
height: 600
Item{
id: contentContainer
anchors.fill: parent
anchors.margins: 4
}
}
在此之前,请原谅我,但功能代码是用C ++编写的,但我认为这个概念可以很好用。我做了一个缩短版本的过程,我希望它可以移植到python。
为了加载ContentFrame组件,我使用了一个从QQuickView(ViewManager)派生的类,它有一个名为setView的方法。此方法加载一个组件(在您的情况下为Launcher或Game),将其设置为contentContainer
的子项并将其设置为anchor.fill
以填充整个父项。
ViewManager::ViewManager() : QQuickView("ContentFrame.qml")
{
// More ctor code
}
// Other stuff
void ViewManager::setView(const QString &filename)
{
QQuickItem *mostTopItem = rootObject(); //QQuickView::rootObject() method
QQuickItem *contentItem->findChild<QQuickItem*>("contentContainer");
if(m_current != NULL)
{
m_current->setProperty("visible", false);
}
// Call a method to load the component and create an instance of it
QQuickItem *newItem = createOurComponentFromFile(filename);
newItem->setProperty("parent", QVariant::fromValue<QObject*>(contentItem));
// When "delete item" in C++, the object will be destroyed in QQmlEngine
// in pyqt???
QQmlEngine::setObjectOwnership(newItem, QQmlEngine::CppOwnership);
newItem->setProperty("anchors.fill", QVariant::fromValue<QObject*>(contentItem));
// Cleanup current object
if(m_current != NULL)
{
delete m_current;
}
m_current = newItem;
}
还有更多代码,但ViewManager的核心是这种方法。我不会在这里致电QQmlEngine::clearComponentCache()
,因为我不止一次加载相同的组件,但在您的情况下,这可能是一个好主意。