(C#) Wie Button einen numpad(0-9) Hotkey zuweisen?
Hallo.
Ich habe 2 Buttons welche auch schon voll funktionsfähig sind. Ich möchte jetzt aber für diese Buttons jeweils einen Hotkey hinzufügen damit man nicht im Form selbst auf den Knopf drücken müsst. Hab ein wenig recherchiert und heraus gefunden das man "UseMnemonic " bei den Buttons benutzen kann. Das ding ist,
- Das einzige was ich gefunden habe ist &Edit was zwar funktioniert, aber ich möchte wie gesagt das Numpad / die zahlen auf dem Numpad nutzen und nicht alt + e. Ich finde jedoch nicht eine einzige liste in dem ähnliche aufgelistet werden.
- Ich möchte das man das im Text nicht sieht. Momentan ist es nämlich so das wenn ich zb. &Edit im Text benutze der Hotkey alt + e wie schon gesagt funktioniert, allerdings sieht das &Edit im Text absolut hässlich aus.
Eventuell gibt es ja auch eine andere Methode.
Ich habe bis jetzt allerdings nur das mit dem "UseMnemonic" gefunden.
Würde mich über jede Hilfe freuen.
2 Antworten
Nutze on key press und dann button.click(). Da natürlich eine if Abfrage einbauen, die den Key checked
Nein, weil ich am Handy bin. Dort geht das nicht so gut. Womit arbeitest du überhaupt? WinForms?
Windows Forms App mit .NET 6.0 in Visual Studio
Im Windows forms designer, bei den Eigenschaften, dort ist ein Blitz. Klick den an. Da findest du alle Events zum ausgewählten element. Wähle die Form für die Form Events. Dann suche da das von mir genannte event
Habe KeyPress gefunden, Drauf geklickt und dann hat es eine Referenz in meiner from erstellt. Aber wie geht es jetzt weiter? Außerdem benötige ich ja noch den namen des Keys, also in meinem fall eines von denen auf dem numpad
private void materialSwitch1_KeyPress(object sender, KeyPressEventArgs e)
{
}
}
KeyPressEventArgs nehme e und Frage den Key ab. if (e. Und dann zeigt visual Studio Vorschläge
Aber was soll ich dann nehmen? Wie geht es dann weiter?
e.GetHashCode
e.Equals
e.GetType
e.Handled
e.KeyChar
e.ToString
also
if (e.KeyChar == );
aber was soll ich dann angeben? Es werden einfach nur ein Haufen an Sachen vorgeschlagen.
KeyPress bietet nicht den passenden sehe ich gerade. Du kannst einen char angeben, der fragt aber nicht ab, ob es vom Nummernfeld kommt. Alternativ, habe ich gerade geschaut, kannst du das KeyUp Event benutzen: (KeyDown geht auch, würde aber Up empfehlen)
private void Form1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.NumPad0))
{
// Action
}
}
Ich habe testweise als Aktion eine messagebox hinzugefügt, allerdings passiert nichts wenn ich numpad0 drücke/los lasse
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.NumPad0))
{
MessageBox.Show("Klappt");
}
}
Nein. Wie schon gesagt.
Ich habe es aber gerade noch mal probiert und zwar habe ich statt Form1_KeyUp direkt den switch genommen. Also in meinem fall, materialSwitch1_KeyUp. Das funktioniert. Allerdings klappt das nur wenn ich denn Switch einmal an gemacht habe. Vorher geht es nicht wieso auch immer. Danach kann ich den switch aber auch aus machen, der hotkey geht dann immer noch was ja so sein soll. Nur das er am anfang nicht geht ist nicht gut
Habe gerade mal was probiert. Ich selber bin auch kein Fan der fertigen WinForm Events, weil die Key Events dort einfach Müll sind und nicht perfekt funktionieren ...
Ich habe mal dieses Script zusammen gebastelt. Es ist nicht die schönste Lösung, funktioniert aber perfekt.
using System.Windows.Forms;
namespace NamespaceVonDeinemProgramm // Hier deinen Namespace rein
{
public class KeyFilterForm : Form, IMessageFilter
{
public bool EnableKeyFilter
{
set
{
if (value)
Application.AddMessageFilter(this);
else
Application.RemoveMessageFilter(this);
}
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x0100)
{
OnKeyDownFilter((Keys)m.WParam);
}
if (m.Msg == 0x0101)
{
OnKeyUpFilter((Keys)m.WParam);
}
return false;
}
protected virtual void OnKeyDownFilter(Keys key)
{
// Nothing
}
protected virtual void OnKeyUpFilter(Keys key)
{
// Nothing
}
}
}
Das fügst du in eine neue CS Datei. Dann kannst deine Form ändern.
Statt:
public partial class Form1 : Form
machst du das:
public partial class Form1 : KeyFilterForm
Jetzt kannst du nach Belieben einfach diese Methoden überschreiben und für dich benutzen:
protected override void OnKeyDownFilter(Keys key)
{
}
protected override void OnKeyUpFilter(Keys key)
{
if (key == Keys.NumPad0)
{
MessageBox.Show("Test");
}
}
Die Methoden werden automatisch getriggert, sobald man einen Key drückt.
Mit einer einfachen if Abfrage, kannst du den Wunsch Key angeben.
Mit:
EnableKeyFilter = true;
Kannst du den KeyFilter an und aus schalten. True = an und False = aus.
public Form1()
{
InitializeComponent();
EnableKeyFilter = true;
}
Alternativ zu meinem Code gibt es noch die:
protected override bool ProcessCmdKey(ref Message message, Keys keyData)
{
}
Siehe Antwort von regex9
Ich persönlich finde aber ProcessCmdKey nicht so aussagekräftig und finde es mit ordentlicher Benamung, wie bei mir schöner. Aber wie du willst. Nimm das, was dir gefällt :)
Vielen vielen dank! Ich habe allerdings noch eine frage. Und zwar wie füge ich das meinem bestehendem projekt bei? Ich habe ja schon eins und möchte kein neues erstellen. Ich meine ich habe ja schon ein namespace, public partial class etc.
Ich sagte ja ...
Du hast aktuell die Vererbung Form. Also du hast da Public partial class DEINNAMEDAFÜR : Form. Hier wirfst du Form raus und setzt dafür KeyFilterForm. Dann hast du direkt die Filter in die Form integriert.
ich benutze nicht die normale form. Ich benutze MaterialForm von dem Material Form 2 NuGet Package. Wie kann ich denn beide gleichzeitig benutzen?
Genau so. Wenn du dir meinen Code anschaust, siehst du da ein : Form, was dort geerbt wird. Das musst du dann durch die Materialform Klasse ersetzen, sodass der davon erbt
public class KeyFilterForm : Form, IMessageFilter
Hier musst du das Form zu MaterialForm (oder wie auch immer die Klasse heißt) ändern und schon übernimmt der diese. Thema Vererbung, gerne Googlen, wenn du dazu mehr wissen willst
Ich verstehe es leider immer noch nicht ganz.
public partial class Form1 : MaterialForm
{
readonly swed swed = new swed();
IntPtr module;
public Form1()
{
InitializeComponent();
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Purple800, Primary.Purple900, Primary.Purple800, Accent.Purple700, TextShade.BLACK);
}
Das ist der oberste teil so wie er jetzt momentan ist. Was muss ich dort jetzt konkret ändern damit ich zb. EnableKeyFilter = true; bei InitializeComponent(); benutzen kann und den rest
Du ersetzt das MaterialForm durch KeyFilterForm und im KeyFilterForm Script, was du von mir kopiert hast, da ersetzt du das Form durch MaterialForm. Dann erbt KeyFilterForm alles von MaterialForm und Form1 erbt das von KeyFilterForm und bleibt damit weiterhin MaterialForm, nur eben erweitert mit diesen Key Features
Ah ok. Wie kann ich so eine neue cs datei öffnen? Muss ich einfach ein neues projekt machen? Also windows forms app und .NET 6.0
Beim Projektexplorer auf dein Projekt rechtsklick > Hinzufügen > Klasse
Wenn ich auf Klasse (Ich habe es auf englisch, also auf Class) gedrückt habe kommt eine liste. Soll ich dort dann auch Class auswählen? oder etwas anderes
Class sollte schon gewählt sein. Du musst nur noch den Namen anpassen unten. Da steht jetzt sowas wie Class.cs oder so. Das passt du an. Pro Datei immer nur eine Klasse und Die Datei und Klasse immer gleich nennen. Wenn du mein Script importieren willst, musst du also die Datei KeyFilterForm.cs nennen
dadurch das ich jetzt aber keyfilterform bei Form1 benutze statt Materialskin bekomme ich bei dem design von form1 nur fehler
"The designer could not be shown for this file because none of the classes within it can be designed. The designer inspected the following classes in the file: The designer could not be shown for this file because none of the classes within it can be designed. The designer inspected the following classes in the file: \r\n Form1 --- The base class 'Kotor_Trainer.KeyFilterForm' could not be loaded. Ensure the assembly has been referenced and that all projects have been built."
Hast du in KeyFormFilter die Form Vererbung geändert gehabt zu MaterialForm?
ja.
public class KeyFilterForm : MaterialForm, IMessageFilter
Ich habe oben extra
using MaterialSkin;
using MaterialSkin.Controls;
Wie bei meiner normalen form benutzt ganz oben
Oh Mann .... Ok, aber macht nichts. Dann ändere es erstmal zurück. Wir müssen da eine Anpassung nochmal vornehmen am script. Kann das am Handy aber nicht, musst also warten, bis ich daheim bin. Scheint, als wenn der Entwickler eine Prüfung eingebaut hat, die das verhindert. Das kann man aber umgehen
Ich vermute mal ich muss irgendwie bei dem KeyFilterForm.cs auch ein
InitializeComponent();
Einfügen. (Material Form braucht das nämlich) Nur weiß ich nicht wo und wie ich das schreiben soll. Habe es schon mit
public KeyFilterForm()
{
InitializeComponent();
versucht aber das hat nicht geklappt
Ne ne. Das ist nicht der Grund. Das ist nur die ausgelagerte Methode zum Form bauen. In die Datei , wo es ausgelagert ist, schreibt der Designer rein
Also das ist wie gesagt das was die normale form für material Skin 2 benutz hat
public Form1()
{
InitializeComponent();
EnableKeyFilter = true;
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Purple800, Primary.Purple900, Primary.Purple800, Accent.Purple700, TextShade.BLACK);
}
Ja, aber das macht nichts. Durch die Vererbung ist es weiterhin erreichbar. Ich baue das Script nachher einmal um und sende es dir dann nochmal
Oh, sorry, vergessen 😅 Gut das du nochmal schreibst. Ich mache mich gleich dran 😅
Das wäre keine gute Methodik. Die Logik sollte stattdessen in einer Hilfsmethode definiert werden, die in den jeweiligen Event Handlern aufgerufen werden kann.
Du kannst dem Form selbst einen Event Handler für das KeyPress oder KeyDown-Event zuordnen. Das Event-Objekt, welches dem Handler als Parameter überreicht wird, besitzt ein KeyCode-Property. Dessen Wert entspricht der gedrückten Taste. Du kannst es also für eine Prüfung auf eine bestimmte Taste nutzen.
Damit das Form das Event auch dann abfängt, wenn eine andere Kindkomponente in ihm fokussiert ist, sollte das KeyPreview-Property zuvor auf true gesetzt werden.
Konträr zum Setzen eines solchen Event Handlers gibt es noch die Lösung, die ProcessCmdKey-Methode zu überschreiben. Die gedrückte Taste steht in keyData.
protected override bool ProcessCmdKey(ref Message message, Keys keyData)
{
// check keyData and return true, if event is handled ...
// otherwise:
return base.ProcessCmdKey(ref message, keyData);
}
Im Vergleich zur erstbeschriebenen Lösung werden auch Ereignisse mit speziellen Tasten (z.B. Enter/Esc) abgefangen, wenn ein anderes Element im Fokus ist (z.B. wenn eine MessageBox / ein Dialog geöffnet ist und mit Enter bestätigt wird).
Die grundsätzliche Logik, die bei Klick oder Tastendruck durchgeführt werden soll, gehört in eine eigene Helfermethode, die dann im jeweiligen Event Handler / ProcessCmdKey aufgerufen wird.
Ich habe noch nie vorher etwas gecoded bis auf in cmd batch falls das zählt und bin ein absoluter Anfänger haha
Wärst du so nett und könntest mir das als code schreiben den in dann einfügen kann?