2015-01-15 22 views
0

我正在研究用qml和pyqt编写的游戏,但应该分为两个窗口(Launcher +游戏)。在这两个qml文件之间切换的正确方法是什么?我不想使用QmlLoader,因为它不会调整窗口的大小,它需要很多信号!我也尝试这种变异:如何更改QQuickView的来源

view.engine().clearComponentCache() 
view.setSource(source()) 

但didn't工作(QML窗口停止工作...... -classic 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() 

正如你所看到的,我的结构是怎么样的混乱,因为我做的第一次该开关的行为,所以我真的不知道,那应该怎么做的权利...每欢迎咨询! :)

回答

2

我不得不在同一时间面对同样的问题。而是一次又一次地使用相同的QQuickView加载相同的组件,我在QML中创建了一个作为内容容器的组件,并将所需的组件作为其子组件加载。每次设置新组件时,我们都会销毁当前组件,并将新组件重新设为子组件。

// ContentFrame.qml 
Item{ 
    width: 800 
    height: 600 
    Item{ 
     id: contentContainer 
     anchors.fill: parent 
     anchors.margins: 4 
    } 
} 

任何东西之前,请原谅我,但功能代码是用C++写的,但我觉得这个概念可以undertood。我做了一个缩短版本的过程,我希望它可以移植到python。

要加载ContentFrame组件,我使用了一个派生自QQuickView(ViewManager)的类,该类具有一个名为setView的方法。此方法加载一个组件(启动器或游戏),将其设置为子项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(),因为我多次加载相同的组件,但在您的情况下,它可能是一个好主意。

+0

谢谢你,它帮了我很多。 – Josef