Temat: "Fader tła dialogu" - może się przyda.

Czasem zdarza mi się pisać aplikację, która ma sporo pól i kontrolek w głównym oknie. Nawet, jeśli jest ono czytelne, to gdy wyświetla się "nad tym" jakiś dialog (lepiej - kilka dialogów), to "mogą się pomieszać oczy", dialog zlewa się z tłem.

Swego czasu, jeszcze za czasów programowania w MFC, natknąłem się na implementację znanego z Windows XP "wygaszania tła", gdy pojawia się dialog z opcjami dotyczącymi zamknięcia systemu. Przez kilka lat nie korzystałem, ale teraz wróciłem do tej koncepcji i bardzo ją sobie chwalę. Bardzo się podobała klientom (i szefowi :) ), ponieważ pozwala bardziej skupić uwagę na zawartości okna no i ciekawie wygląda. Jednocześnie narzut kodu do uzyskania tego efektu jest minimalny.

Nie optymalizowane graficznie, dlatego dla okien zmaksymalizowanych (1280x1024)
chwilę (pół sekundy?) to potrwa. Nie miga (double buffered), ale widoczne jest minimalne opóźnienie przy wyszarzaniu, co jednak zawsze można zgonić na odwołania do DB ;)

Zamieszczam przykładowy kod, który to robi do poeksperymentowania. A nuż się komuś z Was przyda.

namespace xxxxxx.Utils
{
public partial class BackgroundFader : Form
{
private BackgroundFader()
{
InitializeComponent();
}

Form myParent;
public BackgroundFader(Form parent)
{
InitializeComponent();

this.myParent = parent;
}

private void BackgroundFader_Load(object sender, EventArgs e)
{
this.Location = this.myParent.Location;
this.Size = this.myParent.Size;

this.BackgroundImage = new Bitmap(this.Width, this.Height);
using (Bitmap bmpScreenShot = new Bitmap(this.Width, this.Height))
{
this.myParent.DrawToBitmap(bmpScreenShot, new Rectangle(0, 0, this.Width, this.Height));

//UnmanagedFunctions.ImageProcessing.GrayScaleImage(bmp);

System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(new float[][]{
new float[]{0.3f,0.3f,0.3f,0,0},
new float[]{0.59f,0.59f,0.59f,0,0},
new float[]{0.11f,0.11f,0.11f,0,0},
new float[]{0,0,0,1,0,0},
new float[]{0,0,0,0,1,0},
new float[]{0,0,0,0,0,1}});

using (System.Drawing.Graphics g = Graphics.FromImage(this.BackgroundImage))
{
System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
ia.SetColorMatrix(cm);
g.DrawImage(bmpScreenShot, new Rectangle(0, 0, bmpScreenShot.Width, bmpScreenShot.Height), 0, 0, bmpScreenShot.Width, bmpScreenShot.Height, GraphicsUnit.Pixel, ia);
}
}
}
}
}


Atrybuty okna:
* ShowInTaskbar = false
* ControlBox = false
* Text = "" (String.Empty)
* FormBorderStyle = none (inaczej bitmapa będzie przesunięta o kilka pikseli w dół i w prawo)
* DoubleBuffered = true

Okno można by tworzyć gdzieś globalnie i trzymać, a jedynie zmieniać mu rozmiar i rysować na nim bitmapy różnych okien, dzięki czemu nie tworzymy go za każdym razem.

Przykład wykorzystania (z MVC#):

W widoku: (czyli formatce)
[WinformsView(typeof(RegisterPatientRequest_Task), RegisterPatientRequest_Task.wndRegisterPatientRequest_View, ShowModal=true)]
public partial class wndRegisterPatientRequest_View : WinFormViewForRegisterPatientRequestController, IView_RegisterPatientRequest
{

//------------------------ POCZĄTEK ------------------------------------

Utils.BackgroundFader bkgFader;
public void GrayMe(bool gray)
{
if (gray)
{
this.bkgFader = new xxxxx.Utils.BackgroundFader(this);
bkgFader.Show();
}
else
{
this.bkgFader.Close();
}
}
//------------------------ KONIEC ------------------------------------
...........


I to już cały kod w przypadku prostej aplikacji formsowej. Trza danemu oknu po prostu wywołać taką metodę.

Można w dodatku zrobić z niej extension method i nie martwić się przekazywaniem referencji do bieżącego okna.

W MVC# dodatkowo jeszcze:
W prezenterze/kontrolerze (plus dodać def. metody w interfejsie widoku)
public void GrayMe(bool gray)
{
View.GrayMe(gray);
}


I potem w prezenterze dialogu, który ma nam "wyskoczyć" ponad powyższy widok (np. w prezenterze dialogu "Dodaj rezerwację", który ma wyskoczyć ponad widok "Lista rezerwacji"):

// mówimy prezenterowi określonego widoku, żeby wywołał // jego metodę, która pobierze tło widoku, sprowadzi do odcieni szarości, 
// a następnie wyświetli okno o rozmiarach tego widoku i przekopiuje na nie wyszarzoną bitmapę

RegisterPatientRequest_Controller ctrl = ((RegisterPatientRequest_Controller)Task.Navigator.GetController(RegisterPatientRequest_Task.wndRegisterPatientRequest_View));

ctrl.GrayMe(true); // wyszarzamy

......

// wyświetlamy nasz dialog
Task.Navigator.Navigate(RegisterPatientRequest_Task.wndAddEditReservation);

// mówimy prezenterowi w/w widoku, żeby wywołał jego metodę, która zamknie okno z wyszarzoną bitmapą tła

ctrl.GrayMe(false);


Można to oprzeć maszynę stanów (yield true/false) i mieć nieparametryzowaną metodę GrayMe.

Efekt:
Nie rysują mi się na bitmapie 2 kontrolki. Podejrzewam, że ma to związek z z-orderem, chociaż obie są zadokowane i "Bring to front" ani "Send to back" nie działa :o Ale kto będzie na to zwracał uwagę... :]

Oryginalne okno do wyszarzenia:
Obrazek


I z wyszarzeniem:
Obrazek
Zadanie na spostrzegawczość - którego headera (to te paski z tytułami widoków) i jakiego komponentu jeszcze brakuje? ;)

I kilka okien na sobie:
Obrazek


Swoją drogą, to może macie jakiś lepszy sposób na to, bo ten jest bardzo "dosłowny" :)Adrian Olszewski edytował(a) ten post dnia 08.08.10 o godzinie 19:18

konto usunięte

Temat: "Fader tła dialogu" - może się przyda.

Całkiem przyjemne i fajne. Dzięki za podzielenie się tym.
Łukasz Sokólski

Łukasz Sokólski Programista .NET, C#

Temat: "Fader tła dialogu" - może się przyda.

Świetnie to wygląda, super pomysł

Pozdrawiam!
Norbert M.

Norbert M. Nobody's perfect.
Call me Nobody ;)

Temat: "Fader tła dialogu" - może się przyda.

Bardzo ładny efekt. Ja do uzyskania tego celu w aplikacjach WPF stosuje BlurEffect – dodaje ten efekt do parent’a w chwili pojawienia się okna dialogowego i usuwam po jego zniknięciu.
Odradzam manipulacje samym stopniem rozmycia – najlepiej każdorazowo usuwać efekt; oraz stosowanie przezroczystości w oknie dialogowym – potrafi zarżnąć słabsze maszyny.
Nic to odkrywczego, ale gdyby ktoś miał pytania służę pomocą.

konto usunięte

Temat: "Fader tła dialogu" - może się przyda.

Norbert Maziarz:
Bardzo ładny efekt. Ja do uzyskania tego celu w aplikacjach WPF stosuje BlurEffect...

A efekty w WPF'ie nie były/są renderowane software'owo? Czy to tylko dotyczyło BitmapEffects?
Norbert M.

Norbert M. Nobody's perfect.
Call me Nobody ;)

Temat: "Fader tła dialogu" - może się przyda.

Z tego co wiem Extensible Shader Effects (czyli np. BlurEffect) mają pełną sprzentową akcelerację, której nie mają z kolei BitmapEffect. Chyba właśnie tego względu ten pierwszy jest widoczny już w designer’ze natomiast drugi dopiero po uruchomieniu. Nie jestem natomiast pewny co do OS. Wydaje mi się, ze sprzętowa akceleracja wogóle działa dopiero do Vist’y w górę – ale to może mi się jedynie tak wydawać.



Wyślij zaproszenie do