c# how to add contextMenuStrip item at runtime? - c#

I am sure that the answer to this has been posted before. Forgive me as I think I am just not thinking of the right search string.
What I have is a context menu strip assigned to my tray icon for my dialer. The idea is for the user to set various numbers and select the user defined numbers from the menu and initiate the dial.
So the menu pops up with Presets, Setup, & Exit. I want the Presets menu to open a new tree listing the user defined number. I also want this to populate from an xml file every time the application is loaded.
My problem is that I have no idea how to dynamically populate a sub menu item and give it a function.
So how would I at start up add user defined numbers to preset -> (userNumber1, usernumber2, userNumber3) and then call the dial() function when clicked?
So I found how to add to the list... I now feel silly for asking that. For anyone else who wants to know that one, The list item is given a name. Im my case the name attribute is " presetsToolStripMenuItem"
So to add an item to it call the name
presetsToolStripMenuItem.DropDownItems.Add(string text)
No to move on. I am stuck now trying to figure out how to assign an event to that newly added function. I did find
presetsToolStripMenuItem.DropDownItems.Add(string text, image, eventargs)
I am struggling with this one. Maybe I need to stop and come back to it later. Perhaps if someone could provide me with an example of using this line to call a function(); I would be most appreciative.

For anyone that is interested I figured out the solution to adding a context menu item at run time with the ability to call a function.
As stated before, to add a sub menu item to a a parent category, use the parent.name. So in my case the preset menu item name was "presetsToolStripMenuItem"
To add function I used the 3 argument method.
ToolStripMenuItem.DropdownItems.Add("string name", image, eventargs);
so my code looks like this:
presetsToolStripMenuItem.DropDownItems.Add("added2", null, disp);
void disp(object sender, EventArgs e)
{
MessageBox.Show("It works!");
}

Related

How to select multiple elements in a Revit drawing

I'm trying to create a "Multi-Select" method in Revit (for 2016/2017) where the users can select specific parameters of instances contained within a drawing (like Nominal Diameter, Pipe Type and so on), and it will select all the instances within the drawing based on their selections. First, screen shot:
Let's predicate this with the fact that this window is created dynamically based on contents of the drawing. Nothing gets put in this window unless there is an element in the drawing that contains/meets one or more of these parameters.
So, ideally, when I Click the DO IT! button, I would like it to select all of the elements in the drawing that have meet any of these parameters. I can filter through this window and find all of my selections - now I just don't know what do with the selections.
I've looked through the Revit.chm and source and found the Selection namespace and class. There are functions like:
PickObject(ObjectType objectType);
that seem like they would be what I want, but I don't know if it's REALLY what I need. Furthermore, if that IS, in fact, what I'm looking for, I don't know the syntax of how to use it.
A little code:
I have a method that collects all of the users' selections:
private List<CheckBox> GetUserFilterPrefs()
{
//CYCLES THROUGH ALL THE PANELS AND BOXES IN THE WINDOW
return lstCheckBox;
}
Now I want to create my EventHandler for btnDoIt_Click...
I started it, but I'm walking in the dark on this part.
private void btnDoIt_Click(object sender, RoutedEventArgs e)
{
int itr = 0;
GetUserFilterPrefs();
List<Reference> lstRefs = new List<Reference>();
foreach (CheckBox cb in lstCheckBox)
{
if (lstElts[itr].Name == cb.Name)
{
//HOW DO I SELECT ALL ITEMS LIKE THE GIVEN ELEMENT
//THAT ARE RELATED TO THE CHECKBOX SELECTION??
}
itr +=1;
}
I'll obviously keep looking around; but if anyone knows a way, or can point me in the right direction, it would be massively helpful!
THANKS!!!
The PickObject function that you've found is one that asks the user to select an object in the model. Based on your description, that is not what you are looking for.
The function you need is:
SetElementIds(ICollection<ElementId> elementIds)
It is also part of the Selection class. This will highlight the desired elements in the model. To clear the selection in the model, pass an empty List as your argument. Passing null will cause an exception to be thrown.
To focus on the elements, you need the function:
UIDocument.ShowElements
There are a number of overloads for this function. Note that none if the elements are in the currently open view, Revit will attempt to find the best view for you, a task that it generally performs very poorly if there are many views in the model.
PickElement prompts the user for interactive element selection, which is not what you are after.
The one and only way to programmatically access elements in the Revit database is to use a filtered element collector:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.9

Docking an existing QWidget in QWindow

For those who are very familiar with C# or VB.NET using the UserControl component in the .NET Framework (which is the hottest framework in my opinion), you were used to adding several buttons that preview different user controls as follows:
1) First you would prepare an appropriate user interface (contains 3 buttons and a single panel on the right area to view each user control after clicking one of the added buttons).
2) Adding 3 user controls from the solution explorer...
3) Inserting the content on each user control...
4) Implementing code for the 3 buttons on the frmMain.cs as the following (for this implementation we will be implementing the "Welcome" button carrying the object name as welcomeBtn, and the rest will have identical code but different user control names instead):
private void welcomeBtn_Click(object sender, EventArgs e)
{
//Clear up everything from the panel if any item exist(s)...
mainPanel.Controls.Clear();
//Create a new instance of a user control for the button...
UserControl1_Welcome welcome = new UserControl1_Welcome();
//Show up the created instance of the user control
mainPanel.Controls.Add(welcome);
}
5) Finally, the program will end up initially like this when running:
http://i.stack.imgur.com/OENwG.png
** Usage of the program **
When you click on the "Welcome" button for example, the result should be expected to be like this:
http://i.stack.imgur.com/iCyo3.png
... and when you click on a different button, lets say "License Agreement" button, you would expect to see something other than your current selection.
MAIN QUESTION
How can we bring the simplicity of Windows Forms in QT CREATOR by applying the "QDockWidget"?
I have tried inserting the QDockWidget component with no problems, but when I try to do the equivalent .NET code for adding the QWidget inside the QDockWidget:
ui->dockWidget->setWidget(myWidget);
which I think is equivalent to this line of code in C#.NET (correct me if I'm wrong here):
ui.Controls.Add(myWidget);
After using this code, my program won't crash nor shows anything running...
P.S. I'm sorry for linking the images, I don't have 10 reputation for making them show up...
What I want is to have a program that does the same thing with the C# example (showing a user control based on the click of a button).
If you want to show a particular widget based on a button click, I suggest to use a QStackedWidget
A simple example would be like this:
// In the constructor of your CustomWidget
// Create your buttons
QPushButton* firstButton = new QPushButton("First Button", this);
QPushButton* secondButton = new QPushButton("Second Button", this);
QPushButton* thirdButton = new QPushButton("Third Button", this);
// Create your (custom) widgets
QLabel* firstPageWidget = new QLabel("First Label", this);
QLabel* secondPageWidget = new QLabel("Second Label", this);
QLabel* thirdPageWidget = new QLabel("Third Label", this);
// Add them to the stackWidget
/*QStackedWidget* */ m_stackedWidget = new QStackedWidget(this);
m_stackedWidget->addWidget(firstPageWidget);
m_stackedWidget->addWidget(secondPageWidget);
m_stackedWidget->addWidget(thirdPageWidget);
// Insert buttons and stackWidget to CustomWidget
QVBoxLayout* layoutStack = new QVBoxLayout();
layoutStack->addWidget(m_stackedWidget);
QVBoxLayout* layoutButtons = new QVBoxLayout();
layoutButtons->addWidget(firstButton);
layoutButtons->addWidget(secondButton);
layoutButtons->addWidget(thirdButton);
QHBoxLayout* layout = new QHBoxLayout();
layout->addLayout(layoutButtons);
layout->addLayout(layoutStack);
setLayout(layout);
// Connect button clicks to slots
connect(firstButton, SIGNAL(clicked()), this, SLOT(onFirstButtonClicked()));
connect(secondButton, SIGNAL(clicked()), this, SLOT(onSecondButtonClicked()));
connect(thirdButton, SIGNAL(clicked()), this, SLOT(onThirdButtonClicked()));
Then you change the currently visible widget in the slots:
void CustomWidget::onFirstButtonClicked() {
m_stackedWidget->setCurrentIndex(0);
}
void CustomWidget::onSecondButtonClicked() {
m_stackedWidget->setCurrentIndex(1);
}
void CustomWidget::onThirdButtonClicked() {
m_stackedWidget->setCurrentIndex(2);
}
Note that if you want the button clicks just to simply change some text (as opposed to change the visible widget), you probably better use a QTextEdit instead of a QStackedWidget, and in the slots call setText("....");
If you have a lot of buttons, you'd better use QSignalMapper to limit the number of slots.
Also, I didn't get why you mentioned QDockWidget since they have a quite specific usage:
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-level window on the desktop.
QDockWidget provides the concept of dock widgets, also know as tool palettes or utility windows. Dock windows are secondary windows placed in the dock widget area around the central widget in a QMainWindow.
If you simply want a separate window, you're probably looking for a QDialog
How to do this with QtDesigner:
First you would prepare an appropriate user interface (contains 3 buttons and a single QStackedWidget on the right area to view each user control after clicking one of the added buttons).
Adding 3 pages for the user controls in the stack (+ one for the "empty" page if you really need that). If you want to design the Controls in separate UI Files / Only in Code (instead of all controls in your MainFrame), you would add plain QWidgets and promote them to the appropriate specific widget type
Inserting the content on each user control...
Implementing code for the 3 buttons on the frmMain.cpp/.h as the following (for this implementation we will be implementing the "Welcome" button carrying the object name as welcomeBtn, and the rest will have identical code but different user control names instead):
void FrmMain::on_welcomeBtn_clicked() {
ui->stack->setCurrentWidget(ui->welcomeWidget);
}
Select the "empty" page at as the current page in the designer, so the program will end up initially like this when running: (your screenshot)
When you click on the "Welcome" button for example, the result should be expected to be like this: (your second screenshot)
In my opinion, Miki's answer is the only correct approach to this use case (using a QStackedWidget).
For sake of completeness, I'll demonstrate how the same Clear and Add method as used in .NET is done in Qt:
// Assume controlPanel is a QWidget where you want to place the items
// Assume that controlPanel has set a layout (e.g. QHBoxLayout)
// Clear: Remove all Items from layout
QLayoutItem *child;
while ((child = controlPanel->layout()->takeAt(0)) != NULL) {
delete child;
}
// Now widgets are still there, but not layouted. Delete them explicitly
foreach (QWidget * w, controlPanel->findChildren<QWidget*>()) {
w->deleteLater();
}
// Now controlPanel is cleared
// Add new control
controlPanel->layout()->addWidget(new MyNewControlWidget);
First is, we can not force how other framework works to another one. Each framework has its flow and design.
What I am understand is you want to show another widget to the main window.
If you want to use the QDockWidget, its says on the documentation like this :
void QDockWidget::setWidget(QWidget * widget)
Sets the widget for the dock widget to widget.
If the dock widget is visible when widget is added, you must show() it explicitly.
Note that you must add the layout of the widget before you call this function; if not, the widget will not be visible.
Please share here you code of myWidget, so we can try to help you to figure out what is wrong.
On my side, I can achieve it by add the QVboxLayout on your ui->dockwidget and add QLabel with emtpy string and when you want to show myWidget just call ui->dockwidget->vboxlayout->replaceWidget(label, myWidget);

Using an array to navigate to ViewControllers

I'm currently working on refining an app I made for (currently only) IOS. In this app, I have 15 different UIViewControllers, each one of them shows different data and uses different objects.
My menus have a hierarchical structure (not binary). I have 4 "parent" ViewControllers. These parent ViewControllers each have 1 or more "child" ViewControllers:
Roster
EventDetails
Directions
MapView
ChangeRequests
NewChangeRequest
ChangeRequestDetails
Contacts
ContactDetails
ProgressReport
NewReportEntry
DoubleChecks
NewDoubleCheck
DoubleCheckDetails
DoubleCheckPhotoDetails
On the parent ViewControllers I use a FlyoutMenu (with datasource) to be able to navigate to other parent ViewControllers. On the child ViewControllers I have a custom back button, with a delegate attached to it, to take me back to the previous menu. Here come the problem.
I've been given the assignment to link some menus to each other, to improve user-friendliness. an example:
I'm currently at the EventDetails menu. In this menu, I want a button to take me to the NewDoubleCheck menu. Both of these menus have a back button, that uses PopViewController to navigate back to the previous menu. If I'd accessed NewDoubleCheck from DoubleChecks, it would take me back to DoubleChecks. But if I'd accessed it from EventDetails, it takes me back to EventDetails, because it's on the top of the stack. This means I end up in an endless loop of EventDetails --> NewDoubleCheck --> EventDetails --> NewDoubleCheck.
Long story short: I want to be able to search the stack of ViewControllers and be able to select the right ViewController to be loaded, using PushViewController.
I was thinking about writing a method at the start of my app (somewhere near the initialisation of my FlyOutMenu, I'd reckon, that would make me an array of Dictionary<string, UIViewController> with ALL of the ViewControllers in my project, so I can search and navigate more easily. Is this possible?
I know this is a long text, but I'd be glad to hear any opinions and solutions for my problem.
Thanks in advance.
Dear regards,
Björn
I encountered the same problem in one of my apps.
Funny thing is that I checked some of the 'famous' apps on the store, and I noticed that they have this 'endless loop' issue.
My solution was:
Before navigating to NewDoubleCheck, I'd search if it already exists in the navigationController stack.
If that's the case, then I pop to that viewController instead of pushing a new one.
Something like this:
if ([self.navigationController.viewControllers[[self.navigationController.viewControllers count]-2] isKindOfClass:[NewDoubleCheck class]]) {
// ViewController already exist, so we need to get back to it
NewDoubleCheck *viewController = (NewDoubleCheck *)self.navigationController.viewControllers[[self.navigationController.viewControllers count]-2];
[self.navigationController popToViewController:viewController animated:YES];
} else {
// Push to NewDoubleCheck
}
Yes you can get all view controllers like this
NSArray *controllerArray = [[self navigationController] viewControllers];
for (UIViewController *controller in controllerArray){
NSLog(#"%#",controller.title);
}

How can I locate an invisible menu item?

I'm refactoring a body of code, looking through it all, line by line.
I came across an event handler:
private void mnuUpdate_Click(object sender, EventArgs e)
...and, not recognizing which menu item called this (the menu item names do not always match their labels, or even come close), was curious.
The main menu on the form has no such menu item among its children.
I r-clicked the event handler, selected "Find Usages*" and was led here:
this.mnuUpdate.Text = "Update";
this.mnuUpdate.Click += new System.EventHandler(this.mnuUpdate_Click);
(This is an antedeluvial app that predates .NET's partial class goodness, so this is in the same file)
On the form in the designer, when I select "mnuUpdate" from the properties page combobox, the mainMenu on the form disappears altogether.
How can I track down this fugitive menu item? There is no popupMenu or contextMenu on the form, just the mainMenu control...???
The only other usage is:
if (ResetConnectionFetchForm)
mnuUpdate_Click(sender, e);
Is it possible that this is simply a phantom menu item that should be converted into a "regular old" method?
UPDATE
As the most intelligent George used to say, "Curiouser and Curiouser." Now I find this:
public void btnCancel_Click(object sender, EventArgs e)
...and though it is called from seven places in the code, there is no btnCancel on the form...It is a "fake" button click event. Oh my Lanta!!!
So, I replaced it with a parameterless private method with the exact same code (it didn't use either sender or event args).
If the cat who wrote this cockamamie glob of fruitcake-battered spaghetti was deliberately trying to drive the next cat (me) crazy, it's working pretty well, and would make a good Poe-style story or Hitchcock-style flick.
...I see...Dead Code!!!
Okay, mystery solved. mnuUpdate is dynamically added (conditionally) to mnuSetup (which is a top level menu item with the Text property "Fetch") like so:
if (!mnuSetup.MenuItems.Contains(mnuUpdate))
{
mnuSetup.MenuItems.Add(mnuUpdate);
UpdateMenuItemSelectable = true;
}
I reckon selecting mnuUpdate from the combobox in the form's Properties page is because there is no visual representation to show at that point.
Selecting "mnuSetup" highlights the "Fetch" menu item, but selecting "mnuUpdate" causes it all to scurry away faster than cockroaches from the light.
So the bizarre thing about it now is: why is the menu item not dynamically created as necessary, instead of being explicitly created and then dynamically added; seems like a strange way for a cat to skin a cat.
I'd suggest you turn it into "regular old menu" so someone else doesn't waste time figuring it out.
Me - I would have thought it obsolete code because it doesn't have a Handles clause.
You can use .Visible and .Enabled to control what the user sees.

How to disable ToolStripMenuItem in Context menu Dynamically?

In my windows application i have a context menu with a grid the problem is that I want to disable the ToolStripMenuItem in context menu according to the user previlages.How can i do that. i have done like this but it is not working
private void contextMenuStrip_Machine_Opening(object sender, CancelEventArgs e)
{
toolStripAuthorize.Enabled = INFOpermission.accessAuthorize;
}
but it is not working
You need to set toolStripAuthorize.Enabled to either true or false.
I have no idea what INFOpermission.accessAuthorize is because you didn't show the code that defines that (enum?), but if it's anything other than false, this isn't going to work out like you expect.
I can guarantee that setting the Enabled property of the ToolStripMenuItem that you want to disable to false in the Opening event handler will work. If it's not working for you, you're doing something else wrong, and you need to give us some more information to go on.
If you're stuck, see the sample code here: How to: Handle the ContextMenuStrip Opening Event
EDIT: Armed with new information provided in the comments, I've now isolated the source of the problem. You've assigned the ContextMenuStrip to the RowTemplate of a DataGridView control, and are therefore not able to modify items contained in that context menu in its Opening event handler method.
It turns out that this is a known bug that someone decided was "by design". You can see the original bug report here on Microsoft Connect. The explanation given is that whenever a new row is created based on the RowTemplate (which is how the RowTemplate works), the ContextMenuStrip that you've assigned gets cloned as well. That means the same context menu instance is not used for each row, and whatever properties that you try to set on the original menu items have no effect.
Fortunately, it also gives us a workaround. Like all events, the Opening event passes the actual instance of the ContextMenuStrip that is about to be opened as its sender parameter. This is the context menu whose items you need to modify in order for your alterations to be visible.
So what's the code? It looks like this:
private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
{
ContextMenuStrip cmnu = (ContextMenuStrip)sender;
cmnu.Items[1].Enabled = false;
}
Notice, though, that you'll have to reference the individual menu item that you want to modify by its index. This is just the zero-based position of the item in the menu that you want to modify. You can't use the toolStripAuthorize object like you were trying to do before because a new instance of it has been cloned for each new context menu instance.

Categories

Resources