Как изменить источник QQuickView
Я работаю над игрой, которая написана на qml и pyqt, но должна быть разделена на два окна (Launcher + the Game). Как правильно переключаться между этими двумя файлами qml? Я не хочу использовать QmlLoader, потому что он не изменяет размеры окна и требует много сигналов! Я пробовал также этот вариант:
view.engine().clearComponentCache()
view.setSource(source())
но это не сработало (перестало работать окно 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()
Как вы, наверное, видите, моя структура хаотична, потому что я делаю это переключение впервые, поэтому я не знаю, как это следует делать правильно... Любой совет приветствуется!:)
1 ответ
Мне пришлось столкнуться с той же проблемой то же самое время назад. Вместо этого загрузите тот же компонент, используя тот же 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()
здесь, потому что я загружаю одни и те же компоненты более одного раза, но в вашем случае это может быть хорошей идеей.