2015-01-15 7 views
0

Я работаю над игрой, которая написана в qml и pyqt, но должна быть разделена на два окна (Launcher + the Game). Каков правильный способ переключения между этими двумя qml-файлами? Я не хочу использовать QmlLoader, потому что он не изменяет размер окна и ему нужно много сигналов! Я пытался также такой вариант:Как изменить источник QQuickView

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

но didn't работу (окно QML перестал работать ... -Классик ошибка окна, однако ошибка не была написана в 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. Этот метод загружает компонент (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(), потому что я загружаю одни и те же компоненты более одного раза, но в вашем случае это может быть хорошей идеей.

+0

Спасибо, мне это очень помогло. – Josef

 Смежные вопросы

  • Нет связанных вопросов^_^