We are developing QT cross platform application. Application has many functional Screens and navigations. For simplicity of handling screens we are using QT QML StackView. Each item pushed to StackView is Page. I am using following function to push and pop screens.
stackview.push(someurl); //push new url
stackview.pop(); //pop current URL or page
My Question is how can we reuse Components/Pages already pushed on to the stack?
Example : I have following screens A, B, C, D. stack is looking like A->B->C->D. Now from screen D i want to navigate to Screen A. Due to uniform architecture of the application i don't want to do 3 times pop(), instead application should reuse already pushed Screen A and bring it to top.
We can simply push the screen A to StackView (A->B->C->D->A), but we are connecting different Signal/Slot to/from each screen and it will not be good practice to connect every time screen is pushed, also don't want to grow the application StackView size.
What will be the best approach to use in this case ? Any other QT Component/Control which i can use in this case so that i can render Pages depending on Index?
We tried creating component in advance as qml Property and push it depending on URL. It is useful worked great in sample application. but in our application QML component data is closely dependent on C++ data( or some calculations at run time). Application is causing crash if we create component in advance. So we are not willing to use that approach.
property Page page1: Screen1{} //Screen1.qml
property Page page2: Screen2{} //Screen2.qml
property Page page3: Screen3{} //Screen3.qml
property Page page4: Screen4{} //Screen4.qml
Is it possible to laod Stackview component based on Index, i am not finding anything related to that in documents.
Due to uniform architecture of the application i don't want to do 3 times pop(), instead application should reuse already pushed Screen A and bring it to top.
You don't have to call pop() three times to get back to A. According to the documentation :
Item pop(Item item = undefined)
[...]
item: if specified, all items down to (but not including) item will be popped off. If item is null, all items down to (but not including) the first item will be popped. If not specified, only the current item will be popped.
Only call pop(null) once to have your stack going to the first A pushed.
An other possible approach is to use StackLayout that allow you to display QML Components based on an index.
StackLayout {
id: layout
Screen1 {}
Screen2 {}
Screen3 {}
Screen4 {}
}
Then you can select which screen appears by changing the currentIndex property : layout.currentIndex = 1 // display Screen2
Related
I searched on the forum and I don't find a solution for my issue. So I hope you can help me :)
I work on a personal project for SFC designing (Sequential functional chart) and I'm working with visual studio in SDI(I'm using MFC library). If you see the "design" of an SFC you can see the different elements needed to compose this. So you can find Step, Transition, and more. If I take a step for explaining my issue, after double click on the step a popup dialog is opened with the elements to define this step (actions on this step, and more). The issue is here, I can't see two or more step elements at the same time. I want to reuse the existing concept on other software, see this.
Step close
Step open
Dialog to add
My question is, how I can implement a dialog with my graphic element in mainframe (In this case, a step)? I don't know how I can insert a dialog with my element, I think I need to use CFormView, but I don't know.
This dialog needs to be resizable and reduce directly by the step graphic.
any idea?
Thank you in advance! Sorry for my English ..
Sorry, I think my request is not clear .. (Thank you for your answer)
The context, it's an SDI application with the Document/View architecture. Actually the view is derived from CScrollView.
So, in the document class, you have the different lists of components for make SFC (Steps, transitions and symbols ..). I'm working today on Step element.
The user inserts a new step, the step is draw on the view like this :
enter image description here
And now the user want change the events on this Step, for this after double click on the step the events editor is opened at right of step draw, like this :
enter image description here
For this, I've created a new dialog resource and create the class by wizard in CForwView derived class. In step attribute, you can find one instance of this derived class (The derived class of dialog).
But this doesn't work correctly, I think my method is bad. At the first try, I have sent the pointer of the current document to the "CFormView::Create" function for having the "Save" button active with the focus on the FormView. But after destroying the step, the instance of FormView is destroyed and the document with the instance of formview ...
No problem, you can use "Create" within CCreateContext a null pointer. But with the document or without I have a lot of problems (graphic design not correct in FormView, regularly (not systematic I have assert fail on Proc exchange (for differents reason)). But the "concept" is good, the editor follows the draw if I scroll, I can open or close the editor at any time and on any elements.
For the old capture, it's my SFC designer "model". My application is a complement to this application, so I want a similar design. I don't know how work my model application ..
On my application all is draw by MFC GDI, I don't use ActiveX or other tools.
So what is the correct way to implement one instance of editor by instance of step ?
For the implementation on this FormView I have :
- Make new dialog in ressource
- Create a derived class of CFormView with the created dialog
- Add one instance in attributes of Step element
- "OnDbClickOnStep" -> Call "Create" with the good position / size, pointer of mainview (in my case the CSrollView derived class)
- Done, FormView inserted in a mainview, I can edit my step events.
? Not done, I lost save button and other function linked to the document with the focus on a control in FormView. The app want a document with this view, how to override this ?
? Error in Proc exchange, for different reason...
You have an idea ?
You normally don't draw anything in the "main frame" (or the "MDI clild frames", in the case of a MDI application), this is done by the library, and imo sufficiently so. You display your data in a CView-derived class.
CView is the base class of all other MFC view classes. It's a simple graphical class - you need to paint it yourself in the OnDraw() member.
CScrollView is a descendant of CView, adding scrolling functionality (scroll-bars are automatically displayed if the scrollable area is bigger than the visible window area).
CFormView is a descendant of CScrollView, displaying a dialog resource-script, containing "controls" (edit-boxes, check-boxes, images, ActiveX etc).
As in your case the "controls" won't be initially known (except maybe for some few special cases) and rather programatically created, the resource script will most likely be empty, so using either CFormView or CScrollView will basically be the same. I would suggest starting with CFormView, and "downgrade" it to CScrollView if CFormView is not necessary or causes you troubles.
What are those "Step" items shown in the pics? ActiveX controls, child dialogs maybe? These work best as child controls on a dialog window. Are they already implemented, or they are just pics of some other software? Btw ActiveX is a way to define controls that can be used in other projects too, without having to include them in the project source.
I'm rather new to C++, I have a bit of experience with MCV programming in Java. im using GTKmm on C++
What I'm trying to do is writing an application for teaching assistants to submit and edit applications to various positions, and administrators to come in view, and accept these applications.
What I'm trying to do at the begging is create 3 'frames' (I'm working on the submitting application for students only at the moment)
This first will have 2 buttons 1 for selecting if you're a student/admin
Upon clicking you're a student I want to hide this frame and show my second frame
The second frame will have another 2 buttons one for creating an application, and the other for editing applications
My core problem is that I don't understand how to switch between the frames, I've written all the code for my Model, and understand everything I want it to do however I cant seem to find how to do this...
My only idea would be to create windows for each of these, make them look all nice w/e, then when a button is pressed have that window close and a string written to file I can access to see which button has been pressed, then open a new window accordingly. Should I do it like this or is there a better way?
I think I can suggest a better/more idiomatic option for any version >= GTK+ 3.10 - which, to be fair, arrived about half a year after the accepted answer.
If you want to switch between widgets one-at-a-time without any accessories like tabs, then a Gtk::Stack seems like a better option. Because it's specifically geared for one-at-a-time presentation, without any redundancy and (theoretical) overhead from a Notebook's manual tabbing features, which you'd just be disabling straight away! It's a container with multiple children, with one visible at any given moment, and of course methods to change the active child.
You can hook up your own widgets and/or events to manage which of the Stack's children is shown. Alternatively - albeit possibly just restoring the redundancy in this case - there's a StackSwitcher companion widget, which is pretty much a vertical tab-bar as seen in the GTK+ demo and GNOME Tweak Tool.
Easiest way is to use a Notebook widget. You can hide the tabs since you will be controlling which page is showing, using method set_show_tabs(false). Put the top level widget for each of your frames in a pane using method append_page(), and switch between them using set_current_page(). You might want to hide the notebook's bevel if it's distracting, using method set_show_bevel(false).
Use signals to make a widget (e.g. "I'm a student" button) on one page do something (e.g. go to the second page). If you don't know what this means or how to do it, go through the gtkmm tutorial, it will explain this and more.
A bit too late ! But here is my try :
Gtk::Notebook is great but it is not ideal in switching between app frames on menu item clicks. Gtk::Stack, since gtkmm 3.10, exists to mitigate this. Assuming you're using glade and Gtk::Builder :
class
class AppName : public Gtk::ApplicationWindow
{
public:
//...Your app methods and callbacks
void on_mb_itemname_selected(); // The call back for our menu item click/select
private:
//Builder which will help build the app from a .glade file
Glib::RefPtr<Gtk::Builder> _builder;
//...
//Your menu item to activate a particular frame
Gtk::MenuItem * _mb_itemname;
//Your handle to Gtk::Stack which is usually the stack for the whole app
Gtk::Stack * _app_stack;
//...
}
constructor
AppName::AppName(BaseObjectType *cobj,
Glib::RefPtr<Gtk::Builder>& ref_builder)
:Gtk::ApplicationWindow(cobj),_builder(ref_builder)
{
//.. Other setup
_builder->get_widget("your_glade_id_to_stack",_app_stack);
_builder->get_widget("your_glade_id_to_menu_item",_mb_itemname);
// Connect signal_select of our menu item to appropriate signal handler.
mb_itemname->signal_select().connect(
sigc::mem_fun(*this,&AppName::on_mb_itemname_selected));
}
our callback
void AppName::on_mb_itemname_selected()
{
// Change the visible child of the stack concerned.
Gtk::StackTransitionType ttype = STACK_TRANSITION_TYPE_NONE;
_app_stack->set_visible_child("your_widget_name",ttype);
// Note that widget name is not widget glade id.
// You can set your widget under name Packing -> Name
return;
}
I am displaying a ListView cntrl in a modal Dialog box, with ListView properties as "Owner Draw" and "Owner Draw fixed" and using LVN_GETDISPINFO. The dialog along with the list view is getting displayed when there is no data. But strangely, when I am trying to insert data into the list view (by putting data in the array (vector) attached with the list view), my dialog is crashing.
On debugging, the error seems to be coming from the following MFC Library function :
void CListCtrl::DrawItem(LPDRAWITEMSTRUCT)
{
ASSERT(FALSE);
}
In my other applications I have successfully displayed a list control (with Owner draw and Owner data), without subclassing CListCtrl, and overidding DrawItem(). But in my present dialog, I am unable to understand why the list view is failing when I am inserting data into it?
Appreciate your time and help.
Thanks
when you define Owner Draw property, you must implement your own DrawItem function witch draw one item.
You can look for this article
How do I persuade the MFC Doc/View architecture to let me simultaneously display two different views of the same document?
For example, say my CDocument sub-class represents an archive of some description.
I want a UI where the names of all the entries in that archive are presented in a CListView sub-class in the left hand pane, while the details of the currently selected entry are displayed in a CEditView sub-class in the right hand pane.
The CSingleDocTemplate only seems to allow for connecting up one document, one frame and one view. I still want an SDI application, but I want one document and two different views - isn't that the whole point of a good Doc/View architecture?
SDI means "Single Document Interface", it restricts you to only one single document at a time but not in the number of views you can open for this document.
The probably most common approach to open multiple views in an SDI application are Splitter Windows.
You add one view to the CSingleDocTemplate (it doesn't matter which one)
pDocTemplate = new CSingleDocTemplate(
IDR_MYRESOURCEID,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrameWnd),
RUNTIME_CLASS(CMyListView));
Your frame window gets an instance of a CSplitterWnd m_wndSplitter and you overload the OnCreateClient virtual function:
BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
VERIFY(m_wndSplitter.CreateStatic(this,1,2)); // one row / two columns
VERIFY(m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CMyListView),
CSize(300,300),pContext));
VERIFY(m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CMyEditView),
CSize(300,300),pContext));
return TRUE;
}
This example creates a splitter window with one row and two columns. On the left side in the splitter is a view of type CMyListView and on the right side is a view of type CMyEditView.
You can even nest multiple splitter windows one in each other to create arbitrary complex view collections in the frame window.
Here is a small tutorial which shows how to work with splitter windows in a SDI application:
http://www.codeproject.com/KB/splitter/splitterwindowtutorial.aspx
Edit
Wiring up of the views you add to the splitter with the document does MFC internally: CCreateContext* pContext which is passed into OnCreateClient contains a reference m_pCurrentDoc to the current document (the Framewindow knows about this document). MFC uses this in CView::OnCreate (ViewCore.cpp) to add the View to the Document: m_pCurrentDoc->AddView(this) and to set the document pointer m_pDocument in the View.
Therefore subsequent calls of UpdateAllViews of your document will take care of both views.
Revised based on comment:
Okay, what you're after is a static splitter window. The easiest way (I know of) to create this is to start with an SDI MFC project, and tell it that you want a splitter window (in the AppWizard, under "User Interface Features", check "Split Window"). That will create a dynamic splitter -- i.e., it starts with only one pane, and you can create a second by dragging the splitter bar -- but when you do, you'll just get two identical views (though you can scroll them separately from each other).
Then we have to do a little work to turn that from a dynamic splitter into a static splitter. It's probably best to start by looking at the code for the dynamic splitter. If you look in that app's CMainFrame, you'll find that it has:
CSplitterWnd m_wndSplitter;
If you look in the main-frame's OnCreateClient, you'll find something like this:
return m_wndSplitter.Create(this,
2, 2, // TODO: adjust the number of rows, columns
CSize(10, 10), // TODO: adjust the minimum pane size
pContext);
This is what we need to change -- the Create is what creates the dynamic splitter. We need to get rid of that, and create a static splitter instead. The first step to do that is create another view class -- right now, we have only one view class, but we want two, one for each pane.
The easiest way (that I know of) to create our second view class is to run a second copy of VS, and create another (separate) application. We'll tell it to base the view class for that application off of CListView. We'll then take the files for that view, and add them to our original project. To make it easy to hook things up, we want to make sure this second project uses the same name for its document class as the first one did though.
At that point, we have the code for our second view, but it's not connected to anything else, so the view it creates won't be visible. To make it visible, we need to include its header into the CMainframe.cpp (or whatever name it has in your target project). We then get back to the OnCreateClient, and replace the code quoted above with something like this:
CRect rect;
GetClientRect(&rect);
BOOL ret = m_wndSplitter.CreateStatic(this, 2, 1); // 2 rows, 1 column of views
// row 0, column 0 will be the "OriginalView". The initial split will be
// in half -- i.e., each pane will be half the height of the frame's client
//
m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(OriginalView), CSize(1, rect.Height()/2), pContext);
m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(ListBasedView), CSize(1, rect.Height()/2), pContext);
For the moment, I've created a horizontal split, with the "OriginalView" in the upper pane, and the "ListBaseView" in the lower pane, but (I think) it should be fairly obvious what changes to make to rearrange the views.
From there, of course, you'll have to write the code in each view to do whatever it is that view is supposed to do -- but since each is still a separate, normal view, each is reasonably independent, so the development is about like normal. The only significant difference is that you must follow the rules for invalidating your document, and (especially if one of the views is expensive to update) you may want to consider using hints to tell what part of the data has been invalidated so you can write each view to update only what's needed instead of just re-drawing all its data every time.
I am currently writing a wizard-style application using Qt4. I am not using the wizard class however, since going next/back does not make sense from every step in the process.
The user starts off at a "hub"-window with five buttons, each of which take him to another window at a different stage of the process. At the beginning all but the first button of the hub are disabled. After clearing each stage, the user will be directed back to the hub and one new button/stage will get enabled.
Since every stage has significantly differing objectives, I coded every single stage as a single QWidget that gets instantiated in the main() function. To switch between the widgets, I simply hide() the one I am leaving and show() the one I am going to.
However, this leads to problems if the user resized or moved one widget, since the next widget will always show up at its default position instead of the new one.
Is there a way to synchronize the widgets' sizes and positions?
Or, better yet, is there a more elegant way to deal with those different windows than switching between several hidden widgets?
Thank you in advance!
Create one top-level widget that holds the others.
I suggest that you either use QStackedWidget, or, if you want more control, create your own widget and use QStackedLayout directly.
Why not just have one main QWidget as a container for your pages? That way if the user moves the main QWidget and then goes to the next page, it will still open in the new position inside the main widget.
Generally, I've never had occasion to create multiple widgets inside my main method. Don't quite see the point.
I'm beginning on something similar - with different views (perspectives) for different tasks along the way. Using toolbar icons and file menu, not buttons, to move between views. Similar to how MS Outlook allows you to have the window display email, or a calendar, or contacts, etc.
My intent (haven't started yet) is to have one QMainWindow as the application window, containing my various QWidgets that offer the various views. Depending on what task the user is doing, one composite widget will be visible, and the others hidden.