EtienneCmb / visbrain

A multi-purpose GPU-accelerated open-source suite for brain data visualization
http://visbrain.org
Other
241 stars 64 forks source link

Brain app embedded in a PyQt5 GUI #92

Closed zhengliuer closed 3 years ago

zhengliuer commented 3 years ago

Hi, I am trying to build a GUI interface, and want to embed the Brain in it for its practical interaction. But the brain is a QApplication instance, I cannot just embed it in my GUI directly, and I've found this part, image It seems that this place makes it a QApplication, but how do I change it? If the Brain can be not a QApplication, it might solve it.

zhengliuer commented 3 years ago

If I don't change anything, when I click the button to show the Brain, it will show, but after closing it, the app will crash, and showing this image Basically, it looks like running an app in an app

zhengliuer commented 3 years ago

Hi, I've changed my plan to use SceneObj to show the figure. I want to use visbrain in the GUI using PyQt5, and y procedure is right-clicking on the data, and there is an option to plot the electrodes in an MNI brain, like B1, but when I close my app, an error shows up and it says

WARNING: QCoreApplication::exec: The event loop is already running
WARNING: QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
Windows fatal exception: access violation

Current thread 0x0000837c (most recent call first):

So it has something to do with the thread, but I don't know how to fix it. I'll try ubuntu, either.

zhengliuer commented 3 years ago

Here is the code

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QPushButton
from visbrain.gui import Brain
from visbrain.objects import BrainObj

class Test_Win(QMainWindow):

    def __init__(self):
        super(Test_Win, self).__init__()
        self.init_ui()

    def init_ui(self):

        self.setFixedSize(400,150)
        self.center()
        self.create_widget()

    def center(self):
        '''set the app window to the center of the displayer of the computer'''
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def create_widget(self):
        self.play_btn = QPushButton('Display')
        self.play_btn.clicked.connect(self.play_brain)
        self.setCentralWidget(self.play_btn)

    def play_brain(self):
        b_obj = BrainObj('B2')
        self.brain = Brain(brain_obj=b_obj)
        self.brain.show()

if __name__ == "__main__":
    app = QApplication (sys.argv)
    GUI = Test_Win()
    GUI.show()
    app.exec_()

If anyone could have a look at this would be great.

EtienneCmb commented 3 years ago

Hi @BarryLiu97,

Brain is already a GUI so I don't think you can embedded a GUI inside a new one. What you can do is embedded visbrain's objects inside a GUI (like this is the case in Brain where you can display BrainObj).

Inside Brain it's relatively complex because there are multiple objects. In short :

As this is not a Visbrain's issue but something you want to implement, I close this issue. I hope the bullet points are going to help you to make your personal GUI.

cboulay commented 3 years ago

I am working on embedding visbrain in custom widgets in a pyqt/pyside QApplication. Thanks to your advice @EtienneCmb , I think I've got it. Here is a snippet putting it together:

import sys
from qtpy import QtWidgets
from vispy import scene
import vispy.visuals.transforms as vist
import vispy.scene.cameras as viscam
from visbrain.objects import BrainObj
from visbrain.objects import VisbrainCanvas

class TestEmbedVisbrainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Embed BrainObj in custom widget")

        self.resize(QtWidgets.QDesktopWidget().availableGeometry(self).size() * 0.7)

        # From the top of `Brain` __init__
        self._gl_scale = 100.
        self._camera = viscam.TurntableCamera(name='MainBrainCamera')

        # Brain has several mix-in classes and we need to reproduce some of their __init__s.
        # From UiInit.__init__
        bgcolor = (0.1, 0.1, 0.1)
        cdict = {'bgcolor': bgcolor, 'cargs': {'size': (self.width(), self.height()), 'dpi': 600,
                                               'fullscreen': True, 'resizable': True}}
        self.view = VisbrainCanvas(name='MainCanvas', camera=self._camera,
                                   **cdict)
        self.setCentralWidget(self.view.canvas.native)  # instead of Brain's layout: self.vBrain

        # From Visuals.__init__
        self._vbNode = scene.Node(name='Brain')
        self._vbNode.transform = vist.STTransform(scale=[self._gl_scale] * 3)
        self.atlas = BrainObj('B3')
        self.atlas.scale = self._gl_scale
        self.atlas.parent = self._vbNode

        # Cameras
        self.view.wc.camera = self._camera
        self._vbNode.parent = self.view.wc.scene
        self.atlas.camera = self._camera
        self.atlas._csize = self.view.canvas.size
        self.atlas.rotate('top')
        self.atlas.camera.set_default_state()

def main():
    app = QtWidgets.QApplication(sys.argv)
    window = TestEmbedVisbrainWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()