0

私は qml と pyqt で書かれたゲームに取り組んでいますが、2 つのウィンドウ (ランチャー + ゲーム) に分割する必要があります。これら 2 つの 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()

お分かりかもしれませんが、私の構造は混沌としているようです。なぜなら、私はこの切り替え動作を初めて行うからです。そのため、どのように正しく行うべきか、よくわかりません...すべてのアドバイスを歓迎します! :)

4

1 に答える 1

2

私は同じ時間前に同じ問題に直面しなければなりませんでした。同じコンポーネントをQQuickView何度も何度もロードする代わりに、コンテンツ コンテナとして QML でコンポーネントを作成し、必要なコンポーネントをその子としてロードします。新しいコンポーネントが設定されるたびに、現在のコンポーネントを破棄し、新しいコンポーネントを再度子として設定します。

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

先に失礼しますが、関数コードはC++で書かれていますが、概念は理解できると思います。プロセスの短縮バージョンを作成しました。Python に移植できることを願っています。

ContentFrame コンポーネントをロードするために、setView というメソッドを持つ QQuickView (ViewManager) から派生したクラスを使用しました。このメソッドは、コンポーネント (あなたの場合はランチャーまたはゲーム) をロードし、それを子として設定し、親全体を満たすように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()同じコンポーネントを複数回ロードするため、ここでは呼び出しませんが、あなたの場合は良い考えかもしれません。

于 2015-01-16T08:15:37.700 に答える