Sharing same model in two QGraphicScene instances in Qt - qt

I have an application that displays an editor for a diagram using QGraphicsScene object. I would like to create a read only version of the same dialog but have ability for user to see both at the same time.
SimScene* pScene1 = new SimScene(model); // adds model to scene
SimScene* pScene2 = new SimScene(model); // adds model to scene
QGraphicsView* pView1 = new QGraphicsView();
pView1->setScene(pScene2);
QGraphicsView* pView1 = new QGraphicsView();
pView2->setScene(pScene2);
When I create 2 instances of QGraphicsScene and use addItem on the second one it removes all the items from the first one. Does Qt support any sort of sharing of model between scenes? Is my only choice to have same scene and try to customize the view? Later one doesn't seem to work because object selection information is within the graphics items being shared so if I disable flags on them they become read only in both views. Any advice is appreciated. Thanks.

If you just want an interactive and a read-only view on your model you can use a single QGraphicsScene and 2 QGraphicsViews. You just have to call QGraphicsView::setInteractive(false) on one of them. That way you don't have to change any item flags.

I think that you're storing QSceneItems in model classes. Because of that pScene1 and pScene2 are trying to share not only the model itself, but also the scene items. This won't work because any scene item can be placed only on one scene at any given moment.
How to fix it? Make model not aware of any GUI. Let it issue changed() notifications whenever something interesting happens.
Then let each SimScene wrap model into whatever QSceneItems it wants, and process changed() notifications.
Example:
Model:
Graph,
Edge,
Vertex
GUI
SimScene,
QEdge,
QVertex,
QSimInfo,
Qbackground, and so on ...

Also, you add pScene2 twice:
...
pView1->setScene(pScene2);
...
pView2->setScene(pScene2);
And allocate memory for the same pointer twice:
QGraphicsView* pView1 = new QGraphicsView();
...
QGraphicsView* pView1 = new QGraphicsView();

Related

How to automatically run a code from javafx new Scene

I am completely new to Java and I am learning it while developing an app for a school project.
Image Link
I want to code the above program. In it ,
The user will click Ready button in screen 1.
Then screen two will appear and an image of a butterfly will be shown in a order given by me[Preset using a CSV file] Like shown in screen 2 and 3.
Finally, a button set will appear in the grid and user has to select the buttons in the order of the butterfly appearance.
I am stuck in finding a way to start screen 2 and automatically play the butterfly sequence.
I tried putting the image.setimage() on the initialize() block in my screen 2 controller with a delay in-between each setimage() . but it dosent work.
Anyone can suggest me a way to handle this kind of task? Thank a lot in advance.
The issues often seen with this kind of code for beginners are doing sleep or some other long-running operation on the application thread to do some animation. However blocking the javafx application thread results in the scene not being updated resulting in a freeze of the gui.
You either need to move the long-running parts of this animation to a background thread and use Platform.runLater for any GUI updates or use something designed for this exact purpose. There are multiple classes that could be useful in the javafx.animation package, but the most convenient of them seems to be Timeline:
Store the sequence of movements in a suitable data structure and use the Timeline to trigger an event handler in regular intervals to update the gui:
List<FieldIndices> fieldIndices = ...
final Iterator<FieldIndices> iterator = fieldIndices.iterator();
final Timeline timeline = new Timeline();
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(1), evt -> {
if (iterator.hasNext()) {
moveButterfly(iterator.next());
} else {
removeButterfly();
timeline.stop();
}
}));
timeline.setCycleCount(Animation.INDEFINITE); // repeat until stop is called
timeline.play();
Now all that's left for you to implement is reading the data to a list and implementing the logic of moving the butterfly to a new position.
Note that I do not actually recommend using more than 2 scenes: The user will expect the same position for the buttons and the "fields" showing the butterfly. If you design 2 fxmls any adjustment to one of the scene would require you to do the same adjustments to the other scene. This makes the layout hard to maintain. The alternative requires you to create the scene in java code, but the repetitive nature of the scenes makes this a good idea anyways. (The alternative is injecting 16 fields to the controller and collecting them into a suitable data structure; This is error prone and any change of one of the buttons would probably require 16 changes in the fxml. Use a nested for loop and you need to write the logic for creating a button only once storing the buttons in e.g. a nested array can be done at the same time...)
As I understand, you wanna play butterfly sequence once 2nd stage is shown...To achieve that, you could try something like:
List positions = new ArrayList(); //places to show butterfly (e.g. table cells)
secondStage.setOnShown(windowEvent -> {
// update UI with Pltform.runLater()
// moveButerflyTo() is your method to place butterfly on given place
positions.forEach(position -> Platform.runLater(() -> moveButerflyTo(position)));
});
I didn't try this but it do the job...

Clone a Scene in JavaFX

Is there a way to clone a scene in JavaFX ?
I currently want to keep a reference of the previous scene but can't find a simple way of doing it (except passing in the previous scene as a parameter to every new class responsible for scene creation).
Heres what I was thinking of doing (this is a snipped of my view controller)
public void switchScene(Scene newScene){
previousScene = currentScene; // something which achieves this without aliasing
currentScene = newScene;
window.setScene(newScene);
}.
However as one can observe this leads to aliasing problems.
Any way to solve this problem ?

QAbstractItemModel in QGraphicsView

I have to create items based on the file system in the directory. it is mandatory that i have to use QGraphicsView and not (QTreeView/QListView) so how i can manage to hold a QModel for the graphicsScene. can any one help me suggest or refer an example of how i can load QFileModel with the QGraphicsScene.
There is only one easy way to do this, add view with model to the scene. Yes, it is still QTreeView/QListView, but you get all advantages of QGraphicsView and QGraphicsScene, such as rotation, interaction etc.
//fill the model and set model to view
ui->tableView->setParent(0);
QGraphicsProxyWidget * proxyView = ui->graphicsView->scene()->addWidget(ui->tableView);
proxyView->setRotation(45);
Result:
You don't need QFileModel for it. Use QDir::entryInfoList to get list of files and QFileSystemWatcher to track modification of file system.

Qt Model-View update view?

I have a model which is updated dynamically not related to the view. Which method should be called on the view to show the current models data?
Example:
StationListModel *model = new StationListModel(dynamic_list);
QListView *view = new QListView;
view->setModel(model); //view set with empty model
view->show();
In some point in time the dynamic_list is populated with new entries via a socket connection (nothing to do with View). How to populate the view with new data?
Model must emit signals to notify views when its data changed. Choose appropriate signals depending on how exactly data is changed:
dataChanged signal forces view to update specific cells, but not to create or remove cells.
layoutAboutToBeChanged and layoutChanged signals forces view to update everything.
signals about adding or removing rows and columns forces view to update accordingly.

how to use QT graphic view for drawing

im trying to use the graphic veiw of QT to draw lines
it's possible to draw a multiple objects in the scene but is it possible to do a (real time lines ) drawing inside the Qt scene , and how ?
a sample code would be highly appreciated
thanks in advance
I'm creating a kind of "Framework" to do this. There are 2 approaches:
Handle mouse messages, create a QGraphicsLineItem object, add to Scene and modify it during the creation process.
Derive QGraphicsScene, create a QGraphicsLineItem but NOT added to scene, draw it when drawForeground, added it to scene after finished the creation.
Because QGraphicsScene will index objects in a BSP tree by default, and it will impact the performance when changing items frequently, you can get higher performance when using the 2nd approach during creation, but more code work.
1) Create GraphicsView and Scene
m_graphScen = new QGraphicsScene;
m_graphScen->setSceneRect(0,0,790,290);
m_graphView = new QGraphicsView;
m_graphView->setFixedSize(800, 300);
m_graphView->setScene(m_graphScen);
2) Create a slot which is doing the following by handling the mouse events:
m_graphScen->addLine(0, 250, 700, 250, QPen(QBrush(Qt::black),1));
m_graphView->show();
Also if you need to write or draw text see here.

Resources