2013-05-23 13 views
6

C'è un modo per creare una finestra degli strumenti in WinForms che, finché il modulo di hosting è attivo, anche la finestra degli strumenti funziona? Un esempio di questo è in Paint.NET:Messa a fuoco permanente per la finestra degli strumenti

Focused tool window

sto usando C# come linguaggio di backend, sotto .Net 4.0.

+0

Cosa ti fa pensare che abbia sempre al centro? Non è così. Una volta cliccato all'interno della finestra principale, l'attenzione è sparita. Stai cercando di nascondere la visualizzazione della finestra focalizzata? Perché questa è la differenza che posso vedere riguardo a queste finestre degli strumenti. – dowhilefor

+0

Allora devo essere ingenuo. Tutte le finestre degli strumenti hanno l'aspetto mirato a loro. Anche i controlli nelle finestre degli strumenti sembrano raccogliere correttamente gli eventi di hover. – Darkzaelus

+0

Ecco cosa intendevo per visualizzazione. Sembrano concentrati. Ma non reagiscono più alla messa a fuoco della tastiera, possono essere testati con la finestra dei colori e la casella combinata. Hai provato a impostare il proprietario sulla finestra principale e a dare lo stile della finestra degli strumenti? – dowhilefor

risposta

2

Il codice sorgente per una versione precedente di Paint.Net è disponibile presso openpdn Fork of Paint.NET 3.36.7

ho cercato di estrarre i loro metodi da che il codice sorgente nel esempio di lavoro più concisa ero capace:

Pinvoking classe:

internal static class Win32 { 
    public const int WM_ACTIVATE = 0x006; 
    public const int WM_ACTIVATEAPP = 0x01C; 
    public const int WM_NCACTIVATE = 0x086; 

    [DllImport("user32.dll", SetLastError = false)] 
    internal static extern IntPtr SendMessageW(IntPtr hWnd, uint msg, 
              IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal extern static bool PostMessageW(IntPtr handle, uint msg, 
              IntPtr wParam, IntPtr lParam); 
} 

Modulo Base:

public partial class Form1 : Form { 

    public Form1() { 
    InitializeComponent(); 
    } 

    private bool ignoreNcActivate = false; 

    protected override void WndProc(ref Message m) { 
    base.WndProc(ref m); 

    switch (m.Msg) { 
     case Win32.WM_NCACTIVATE: 
     if (m.WParam == IntPtr.Zero) { 
      if (ignoreNcActivate) { 
      ignoreNcActivate = false; 
      } else { 
      Win32.SendMessageW(this.Handle, Win32.WM_NCACTIVATE, new IntPtr(1), IntPtr.Zero); 
      } 
     } 
     break; 
     case Win32.WM_ACTIVATEAPP: 
     if (m.WParam == IntPtr.Zero) { 
      Win32.PostMessageW(this.Handle, Win32.WM_NCACTIVATE, IntPtr.Zero, IntPtr.Zero); 
      foreach (Form2 f in this.OwnedForms.OfType<Form2>()) { 
      f.ForceActiveBar = false; 
      Win32.PostMessageW(f.Handle, Win32.WM_NCACTIVATE, IntPtr.Zero, IntPtr.Zero); 
      } 
      ignoreNcActivate = true; 
     } else if (m.WParam == new IntPtr(1)) { 
      Win32.SendMessageW(this.Handle, Win32.WM_NCACTIVATE, new IntPtr(1), IntPtr.Zero); 
      foreach (Form2 f in this.OwnedForms.OfType<Form2>()) { 
      f.ForceActiveBar = true; 
      Win32.SendMessageW(f.Handle, Win32.WM_NCACTIVATE, new IntPtr(1), IntPtr.Zero); 
      } 
     } 
     break; 
    } 
    } 

    protected override void OnShown(EventArgs e) { 
    base.OnShown(e); 
    Form2 f = new Form2(); 
    f.Show(this); 
    } 
} 

Sempre attivo Form2 (a meno che l'app non sia attiva):

public partial class Form2 : Form { 
    internal bool ForceActiveBar { get; set; } 

    public Form2() { 
    InitializeComponent(); 
    this.ShowInTaskbar = false; 
    this.ForceActiveBar = true; 
    } 

    protected override void WndProc(ref Message m) { 
    base.WndProc(ref m); 
    if (m.Msg == Win32.WM_NCACTIVATE) { 
     if (this.ForceActiveBar && m.WParam == IntPtr.Zero) { 
     Win32.SendMessageW(this.Handle, Win32.WM_NCACTIVATE, new IntPtr(1), IntPtr.Zero); 
     } 
    } 
    } 
} 

Non è necessario impostare TopMost su true per Form2 poiché dovrebbe essere di proprietà dal modulo principale quando viene visualizzato. Inoltre, Form2 non è un modulo figlio MDI.

+0

+1 per il link e lo sforzo (non testato) – banging

+0

Questo è molto simile a come la mia soluzione sta finendo! Sono bloccato con qualcosa di strano in cui il modulo genitore diventa inattivo quando si fa clic sul modulo figlio. Ho risolto questo problema forzando l'attenzione sul modulo genitore ma significa che non posso usare i menu a discesa sul bambino. – Darkzaelus

+0

Questo è l'approccio che ho usato per avvicinarmi il più possibile alla soluzione, quindi lo contrassegno come risposta – Darkzaelus

2

Le finestre degli strumenti in Paint.NET sono solo finestre di questo tipo. In termini di Win32, si ottiene ciò creando la finestra con lo stile di finestra esteso WS_EX_TOOLWINDOW:

La finestra deve essere utilizzata come barra degli strumenti mobile. Una finestra degli strumenti ha una barra del titolo più breve di una normale barra del titolo e il titolo della finestra viene disegnato utilizzando un font più piccolo. Una finestra degli strumenti non viene visualizzata nella barra delle applicazioni o nella finestra di dialogo visualizzata quando l'utente preme ALT + TAB.

In WinForms, questo è controllato dalla proprietà FormBorderStyle. Impostalo su FormBorderStyle.FixedToolWindow o FormBorderStyle.SizableToolWindow nel costruttore del modulo.

È inoltre necessario assicurarsi di specificare una finestra del proprietario per la finestra degli strumenti. Il suo proprietario dovrebbe essere la tua forma principale, quella per cui funge da tavolozza degli strumenti. In genere lo fai quando mostri il modulo, utilizzando il sovraccarico del metodo Show che ti consente di specificare una finestra del proprietario.

Infine, un altro effetto interessante che Paint.NET ha (credo, se non ricordo male) è che le finestre degli strumenti non possono mai effettivamente ricevere il focus. È possibile interagire con loro, facendo clic sui pulsanti per selezionare gli strumenti, ma non è possibile impostare effettivamente lo stato attivo su una tavolozza mobile. Torna sempre alla finestra principale. Un tentativo ingenuo di emulare questo comportamento potrebbe essere quello di ripristinare lo stato attivo in una delle notifiche che modificano la messa a fuoco (ad esempio, l'evento Activate), ma non è una buona idea per numerose ragioni. Una soluzione migliore sarebbe aggiungere lo stile di finestra estesa WS_EX_NOACTIVATE. Non sono a conoscenza di alcuna proprietà che espone questa funzionalità in WinForms, ma è possibile impostarla manualmente durante la creazione della finestra ignorando la proprietà CreateParams. Per esempio:

public class MyForm : Form 
{ 
    // ... other code ... 

    protected override CreateParams CreateParams { 
     get { 
      const int WS_EX_NOACTIVATE = 0x08000000; 

      CreateParams cp = base.CreateParams; 
      cp.ExStyle |= WS_EX_NOACTIVATE; 
      return cp; 
     } 
    } 
} 
+0

Sfortunatamente, l'impostazione del proprietario significa che non può lasciare i limiti del genitore, che la barra degli strumenti di Paint.NET può. Ottengono anche l'aspetto "MDIChild", che non è quello che voglio. Penso di aver trovato qualche codice che farà ciò che voglio, ma è pieno di chiamate WinAPI e chiamate goto. Che schifo. – Darkzaelus

+0

@Dark Sembra che tu stia confondendo i bambini MDI e hai finestre di proprietà. Non c'è nulla che impedisca ad una finestra di proprietà di essere spostata al di fuori dei limiti del suo proprietario. Tutte le finestre di messaggio generate dal sistema sono finestre di proprietà e possono essere spostate su tutto lo schermo. –

+0

Devo aver fatto una strana combinazione di stili! Hai ragione, il mio errore – Darkzaelus

0

Non so se Windows Form ha un built-in funzione di questo, ma si può ottenere quello che vuoi con il codice qui sotto:

Per principale forma:

private ToolForm m_toolForm; 

private void MainForm_Load(object sender, EventArgs e) 
{ 
    m_toolForm = new ToolForm(); 
    m_toolForm.Show(); 
} 

private void MainForm_Resize(object sender, EventArgs e) 
{ 
    switch (WindowState) 
    { 
     case FormWindowState.Minimized: 
      m_toolForm.Hide(); 
      break; 

     case FormWindowState.Maximized: 
      m_toolForm.Show(); 
      break; 
    } 
} 

per forma strumento: non è necessario alcun codice, basta impostare la proprietà "TopMost" true.

+0

Questo purtroppo non fa nulla per la mia situazione. Se ti allontani dal modulo, perde il focus – Darkzaelus

Problemi correlati