C#: Windows Forms: Getting keystrokes in a panel/picturebox? - c#

I'm making a level editor for a game using windows forms. The form has several drop down menus, text boxes, etc, where the user can type information.
I want to make commands like CTRL + V or CTRL + A available for working within the game world itself, not text manipulation. The game world is represented by a PictureBox contained in a Panel.
This event handler isn't ever firing:
private System.Windows.Forms.Panel canvas;
// ...
this.canvas = new System.Windows.Forms.Panel();
// ...
this.canvas.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.canvas_PreviewKeyDown);
What is the preferred way of doing this? Can a panel even receive keyboard input? I would like to allow the user to use copy/paste/select-all commands when working with the text input, but not when placing objects in the game world.

From the MSDN documentation for Control.CanSelect:
The Windows Forms controls in the
following list are not selectable and
will return a value of false for the
CanSelect property. Controls derived
from these controls are also not
selectable.
Panel
GroupBox
PictureBox
ProgressBar
Splitter
Label
LinkLabel (when there is no link present in the control)
Although it says controls derived from these controls cannot receive focus, you can create a derived control and use the SetStyle method to enable the "Selectable" style. You also must set the TabStop property to true in order for this to work.
public class SelectablePanel : Panel
{
public SelectablePanel()
{
this.SetStyle(ControlStyles.Selectable, true);
this.TabStop = true;
}
}
Then use this control instead of the normal Panel. You can handle the PreviewKeyDown event as intended.

You'll probably want to do the key capture at the form level. This is highly recommended reading from the person who helped write the underlying .NET code:
http://blogs.msdn.com/jfoscoding/archive/2005/01/24/359334.aspx

Related

Tags in WinForms TextBox

I want to create a textbox on a WinForms form, where the user cannot input text directly. Instead, the content of the textbox should only be "bubbles" (with a "delete" button), showing a text value.
I'm struggeling to find the correct term for this kind of control/behaviour. It should look a bit like the "Tags"-field on StackOverflow when creating a new question.
Are there any existing controls/settings that allow such behaviour? (I have DevExpress if that helps)
Sorry for the vague question, if i knew better terms for what i'm looking for, i'd probably find something...
Instead of a textbox, the container for your bubbles should most likely be a Panel.
You can style it as needed, set the border, background color, etc.
If you don't want to manually position the "bubbles" inside it, use a FlowLayoutPanel. It will automatically put it's children controls in a flow.
Check out the properties of the control to specify how you want controls to be laid out.
The individual bubbles can also be Panels or other container controlls, so that you can add a label and a button (or image to serve as a button) to each.
You might even extend the panel class to automatically add a label and a delete button to each.
something like this (please note this is more like pseudo code. I wrote it up of the top of my head here, some adjustment may be needed)
Public Bubble : Panel {
Public Bubble(string text) {
Label title = new Label { Text = text };
Controls.Add(title);
Button delete = new Button { Text = "Delete" };
Controls.Add(delete);
//also hook up events here, ie delete.click+= whatever
}
}
You can further extend the custom class for your specific needs.
Set styles on the button and label as needed to achive the look you want.
Don't forget to hook up events such as mouse over, button click, etc.
Then just fill the FlowLayoutPanel with these custom controls and you should be good to go

WinForms tooltips not showing up

I have a WinForms application. Each form and user control sets up its tooltips as follows:
// in the control constructor
var toolTip = new ToolTip();
this.Disposed += (o, e) => toolTip.Dispose();
toolTip.SetToolTip(this.someButton, "...");
toolTip.SetToolTip(this.someCheckBox, "...");
...
However, the tooltips don't appear when I hover over the controls. Is this an appropriate way to use tooltips? Is there something that could be happening in another part of the application (e. g. listening to some event) that would stop tooltips from working?
Note that tooltips on my outer form's toolstrip buttons (which are configured via the button's tooltip property) do work as expected.
EDIT:
I've observed this more and I've noticed that sometimes the tooltip does show up, it is just extremely "flaky". Basically, sometimes when I mouse over a control it will show up very briefly and then flicker away. I can get it to show manually with .Show() and a long AutoPopDelay, but then it never disappears!
Your code seems ok to me. I couldnt find anything wrong in your code. But, it could be failed only when control is disabled. BTW, you can try another method like this. but, i would not like to suggest you to show the tooltip like this.
private void someButton_MouseEnter(...)
{
toolTip.Show("Tooltip text goes here", (Button)sender);
}
You can also assign the location where tooltip should be displayed in .Show() method. there are some overloaded function that you can use. Read the msdn for more information about ToolTip.Show() method.
I faced similar issue when my tooltip was not showing up over the RichTextBox once in about 3-5 times it normally should. Even forcing it to show explicitly with toolTip.Show didn't help. Until I changed to the way mentioned by Shell - you have to tell where you want your tooltip to appear:
'Dim pnt As Point
pnt = control.PointToClient(Cursor.Position)
pnt.X += 10 ' Give a little offset
pnt.Y += 10 ' so tooltip will look neat
toolTip.Show(text, control, pnt)
This way my tooltip always appears when and where expected.
Good luck!
I wrote the following method to "propagate" ToolTips from parent controls (that have a tool tip set) to its child controls (unless they have their own overriding ToolTip).
It's designed to be dropped into the form or control you're starting with, but it could also just be turned into a static method where the "parent" argument is required.
/// <summary>Setting a toolTip on a custom control unfortunately doesn't set it on child
/// controls within its drawing area. This is a workaround for that.</summary>
private void PropagateToolTips(Control parent = null)
{
parent = parent ?? this;
string toolTip = toolTip1.GetToolTip(parent);
if (toolTip == "")
toolTip = null;
foreach (Control child in parent.Controls)
{
// If the parent has a toolTip, and the child control does not
// have its own toolTip set - set it to match the parent toolTip.
if (toolTip != null && String.IsNullOrEmpty(toolTip1.GetToolTip(child)))
toolTip1.SetToolTip(child, toolTip);
// Recurse on the child control
PropagateToolTips(child);
}
}
Note that the behaviour is undefined if you're using more than one ToolTip instance to manage parent and child control toolTips.

C# Winforms: how do you set focus to a DataGridView component on a form?

I have a DataGridView component on a form. How do I set the focus to this component so that it responds to arrow keys?
You could:
dataGridView.Select();
or
dataGridView.Focus();
Alternatively, you could set the ActiveControl property:
ActiveControl = dataGridView;
The following text came from Microsoft
Focus is a low-level method intended
primarily for custom control authors.
Instead, application programmers
should use the Select method or the
ActiveControl property for child
controls, or the Activate method for
forms.
U can try with this.
public void SetFocusToDataEntry()
{
_datagridview.Focus();
_datagridview.CurrentCell = _datagridview.Rows[1].Cells[2];
}

C# Winforms - Prevent a control from stealing focus when added programatically

I have a bit of an odd question.
My situation is as following:
I have a form, It contains several user controls that in turn contains either other user controls or other basic controls such as TextBox, RichTextBox and such.
As part of the logic when editing the text boxes, I create another control programatically and inform the form about it. Other controls on the form may react in turn and create more controls.
Trouble is, These controls steal focus from my control when they are created and added to the form/other controls.
Is there a way to prevent my control from losing focus while that happens?
Maybe you should include in the logic, the tab indexes first, and when you add the control, set the tab index to the last tab index + 1, your job would be easier, if you set the tab order first on the controls, and set the constant to the last tab index at design time, see here,:
private const int LAST_TAB_INDEX = 5; // an Example
private int lastTabIndex = LAST_TAB_INDEX;
private void AddControl(){
// Set up your control
Control ctl = new Control();
// ....
ctl.TabIndex = lastTabIndex;
this.Add(ctl);
this.lastTabIndex++;
}
You can see from the example how the tab index is incremented, in that way, it will prevent
the controls from stealing the focus...
Hope this helps,
Best regards,
Tom.
Controls can't accept (steal) focus unless they are visible and enabled. Have you tried creating the controls with one or both of these as false, and then turning them on when appropriate?

winforms panels vs java swing panels

In java swing I can insert panels into panels and so on, and not have to build a brand new window for every view of my applicaiton, or mess around removing and adding controls.
Theres a panel clas sin C# however I cant see any way of creating a 'panel form' or basically just a form in form designer thats a panel and its contents.
How do I do this then and work the way I did with java swing?
Usually i just dock different forms within eachother setting the IsMdiContainer Property to true on the parent window. Then i create subforms that i dock using the following function:
static class FormUtil
{
static public void showForm(Form sender, Control reciever)
{
sender.ControlBox = false;
sender.FormBorderStyle = FormBorderStyle.None;
sender.ShowInTaskbar = false;
sender.TopLevel = false;
sender.Visible = true;
sender.Dock = DockStyle.Fill;
reciever.Controls.Clear(); //clear panel first
reciever.Controls.Add(sender);
}
}
then whenever i need to dock a form inside a panel on the parents form i just do:
FormUtil.showForm(new SomeForm(), this.splitContainer1.Panel1);
This allows me to delegate some of the form creation to different designers. Works like a charm for me, love to hear if theres a better way of doing it.
Actually, you can use the panel control and set it's Dock property to Fill. That way, your panel will be the entire canvas of the form. Then, you can add child panels as needed either through code behind or through forms designer.
There's the concept of user controls which basicly provides you with a panel like designer surface , not to mention that you can create atomic forms (which can be reused) and register them as inheritable, that way you can provide inheritance too.

Categories

Resources