Creating layout & logic AutoCAD plugin dialog - c#

Brand new to AutoCAD plugin development. I'm trying to create a plugin that loads as an entire main menu option inside of AutoCAD (let's call this menu the "Fizzbuzz" menu, and when the user selects one of the menu items (say, Fizzbuzz >> Foobar) I want a simple dialog/window to show up on screen in the top-left corner of AutoCAD.
I'm trying to figure out where the presentation/layout logic for this dialog/popup window needs to go (what file does it live in and how do I create/edit it?), and just as importantly: where the event-driven GUI logic needs to go (again: what file do I edit and in what language?). By "GUI logic" I mean: let's say there's a checkbox or button inside my dialog...when the user clicks/interacts with these UI components, I need custom logic to execute.
Any idea what files house this type of presentation/GUI logic for new AutoCAD plugins and how I create/edit them? Thanks in advance!

I have added a palette hosting a winform control this way:
using System.Windows.Forms;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
namespace AMU.AutoCAD.BlockTool
{
public class MyPalette : IExtensionApplication
{
private PaletteSet palette;
private Control paletteControl;
public void Initialize()
{
//This is called when AutoCAD loads your assembly
this.palette = new PaletteSet("Name")
{
TitleBarLocation = PaletteSetTitleBarLocation.Left,
Style = PaletteSetStyles.Snappable //Your Styles
};
this.paletteControl = new Control(); //Instance of your Control that will be visible in AutoCAD
this.palette.Add("HEADER", this.paletteControl);
this.palette.Visible = true;
}
public void Terminate()
{
//cleanup
this.palette.Dispose();
this.paletteControl.Dispose();
}
}
}
By providing a class implementing the IExtensionApplication you can execute custom code on loading a dll, without explicitly call a method. You now can create a so called PaletteSet and add a Winform or WPF Control to it.

Related

Orc.Memento Global Undo with Multiple Controls

I have a need to implement a memento undo-redo pattern. My application has multiple tabs and in these tabs there are multiple controls which all implement Orc.Memento. The trouble I am having is calling undo with the menu button on MainWindow and in the button action call undo on the last active control.
Edit: this project is unfortunately does not follow MVVM.
I chose Orc.Memento because it is super easy to implement without modifying objects. What I have now is working great only with keyboard commands Ctrl+X & Ctrl+Y. Calling undo only does undo on the active control. However, when I click the undo/redo buttons on the MainWindow menu my code does not know the last active control to call undo/redo on.
Option 1
Option one is to keep track of the last active control by setting a global property on GotFocus() of each control. I feel like there has to be a better way.
Option 2
That is why I am here :-).
Control
public class MyControl : IMemento
{
private MementoService mementoService = new MementoService();
public void RegisterAll()
{
mementoService.RegisterObject(myObject);
mementoService.RegisterCollection(myCollection);
}
public void Undo()
{
mementoService.Undo();
}
public void Redo()
{
mementoService.Redo();
}
}
MainWindow
Ctrl+Z & Ctrl+Y is mapped here. The undo/redo methods find the currently active control and call undo/redo at that control.
public MainWindow
{
/// <summary>
/// Call undo on the currently active control
/// </summary>
public void Undo()
{
/*
* get current focused control.
* find the parent that is an IMemento. And call Redo on that control
*/
var focusedControl = FocusManager.GetFocusedElement(this);
var mementoControl = UIHelper.TryFindParentThatIsIMemento<Control>(focusedControl as DependencyObject);
/*
* Call Undo on the control that is currently active
*/
if (mementoControl != null && mementoControl is IMemento)
{
var mem = (mementoControl as IMemento);
mem.Undo();
}
}
}
Note: If I could program this how Excel works by auto navigating to the control where the undo/redo happens that would be great. It is not necessary, but if you have an idea my ears are open.
Here are a few recommendations:
Try to implement undo/redo against models (e.g. using Orc.ProjectManagement), not against views (since views are short-living
Try to use the TabControl from Orc.Controls, which allows you to keep all the tabs active and thus allowable for redo/undo).

Sub-class a control

So I know how to create sub-classes and call them, however I get lost when I have to call / use a sub-class of a control: For example:
public class KeyboardButton : Button
{
public void SimulateButtonDown()
{
this.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 0, 1, 1, 0));
}
public void SimulateButtonUp()
{
this.OnMouseUp(new MouseEventArgs(MouseButtons.Left, 0, 1, 1, 0));
}
}
As created in this article.
How to I put to use especially when I have multiple control buttons I want to call the method "SimulateButtonDown()".
Are you using WinForms or WPF? For the sake of this answer, I will assume WinForms.
First, add the code you've posted here into your WinForms project somewhere. Then compile it. After doing so, KeyboardButton should be automatically added to your Toolbox. Open a form or user control in the designer of Visual Studio, and you should see a section called "YourProjectName Components". This section should have KeyboardButton in it. Just drag and drop it onto your form or user control.
If you want to replace existing buttons on existing forms or user controls, it may be easier to update the code in xxx.Designer.cs. (NOTE: EXERCISE CAUTION WHEN EDITING xxx.Designer.cs FILES.) In the Solution Explorer, find the form or user control that has the button(s) you want to replace. Expand the node for the form/user control, and you should see a file called something like Form1.Designer.cs. Double-click to open that file. In there, for each existing button, you should see lines such as this.saveButton = new System.Windows.Forms.Button();. Replace System.Windows.Forms.Button with YourNamespace.KeyboardButton. You will also see lines like private System.Windows.Forms.Button saveButton;. Replace the namespace & class name there too.
Once you've got a KeyboardButton on your form/user control, you can call SimulateButtonDown and SimulateButtonUp from within your form/user control just by writing code like saveButton.SimulateButtonUp().

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);

How to get the Custom Task Pane Object on the Ribbon control Class

Developing a Excel vsto project, how could I handle the Custom Task Pane in the Class which is a Ribbon Control.
For example, I would like to show the Custom Task Pane when I click the button of the Ribbon Control.
Dora
I assume you are working with an Excel VSTO add-in, with the Ribbon Visual Designer. You can achieve what you want by making your custom Task Pane accessible via a property on your Add-In:
public partial class ThisAddIn
{
private CustomTaskPane taskPane;
internal CustomTaskPane TaskPane
{
get
{
return this.taskPane;
}
}
... and adding a button in your Ribbon, and adding an event handler for the click event, accessing the add-in via Globals:
private void MyRibbonButton_Click(object sender, RibbonControlEventArgs e)
{
Globals.ThisAddIn.TaskPane.Visible = true;
}
I wrote a post a while back which describes the process, you may find it useful.
This is also feasible using the xml ribbon.
This can be accomplished by having a Win Forms user control.
I've worked on a project where we had to extend MS Word and needed this functionality, but the same example will apply to Excel.
Another interesting way I stumbled upon on the net is to have a Windows user control and host a WPF user control within the Windows control!
This ofcourse allows you to take advantage of all the awesome tools you get with WPF, here is an example:
1)Drop a ToggleButton on a Ribbon(Visual Designer).This will be used to show hide the task pane.
Using ToggleButton is a good choice as it appears highlighted when pressed down.
2)Add below code to the click event of the ToggleButton
Globals.ThisAddIn.TaskPane.Visible = ((RibbonToggleButton)sender).Checked;
3)Add a reference from your project to the following assembly - WindowsFormsIntegration
4)In your ThisAddIn.cs add the two using directives listed below:
using Microsoft.Office.Tools;
using System.Windows.Forms.Integration;
5)Add two user controls
5.1)User control (name - taskPaneControl1)
5.2)User control(WPF),(name - con)
Using the names I've used will help when copying/pasting the code below but by any means change it if you wish to
6)Add below code to the ThisAddIn.cs class
public CustomTaskPane TaskPane
{
get{return taskPaneValue;}
}
private TaskPaneControl taskPaneControl1;
private CustomTaskPane taskPaneValue;
private WpfControl con;
internal void AddTaskPane()
{
ElementHost host = new ElementHost();
con = new WpfControl();
host.Child = con;
host.Dock = DockStyle.Fill;
taskPaneControl1 = new TaskPaneControl();
taskPaneControl1.Controls.Add(host);
taskPaneValue = this.CustomTaskPanes.Add(taskPaneControl1, "My Taskpane");
taskPaneValue.Visible = true;
}
6)Add the two code below to the Startup event in your ThisAddIn.cs
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
AddTaskPane();
taskPaneValue.Visible = false;
}
When an MS Office Application is opened the task pane will be hidden toggle the Visible property to change this in the Startup event.
Navigate to the ToggleButton and press it a few times to make sure the task pane is showing as expected
Also have a look at the following link most of my code came from here - http://xamlcoder.com/cs/blogs/joe/archive/2007/07/17/using-wpf-with-vsto-office-2007.aspx
This is a difficult challenge since the Ribbon and Task Panes are separate entities. One of the main challenges is that there is only one instance of the Ribbon class and multiple instances of the task pane for each inspector. To this properly requires some advanced understanding of the Office internals.
The solution also depends on whether you are using the Ribbon XML or Ribbon Designer. Which approach are you using?

How do I create a class associated with a windows form in C#?

Now that C++ development has become second nature to me, do I have to start from scratch with C#?
Since the beginning of Visual Studio, there has been easy way to describe the shape of a Dialog (now called a Form) in the resource file and then use a wizard to create the corresponding C++ code. I kind of remember that in MFC it was pretty much a no-brainer to create a custom dialog with all the components you want and then all the associated code.
If I have a C# app that has many forms that I want to bring to the screen based on the user's menu selections, how do I create a class associated with a windows form?
If you are using the designer then it generates the C# class for you; so if have a form called UserOptionsForm, you should just need to do something like:
new UserOptionsForm().Show();
or for a modal popup:
using(UserOptionsForm form = new UserOptionsForm()) {
form.ShowDialog(); // returns result code (OK/cancel/etc)
}
In .Net (C#, VB.Net, or whatever .Net language you're using), forms are classes, not necessarily involving resource files at all. Creating a form is as easy as inheriting the Form class:
public class MyWindow : Form
{
}
You can now bring it to the screen:
using (var myWindow = new MyWindow())
{
myWindow.Show();
}
The window will be quite empty until you add some controls to it:
public class MyWindow : Form
{
public MyWindow()
{
var button = new Button();
button.Text = "Click me";
Controls.Add(button);
}
}
As you can see, in WinForms forms and controls are all built up using code. Now coding up forms like this by hand is tedious, so do use the WinForms Designer in Visual Studio. It will generate the code for you.

Categories

Resources