2015-01-15 76 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