Obrazovka (II.) a pracovní plocha v C++

V minulém článku jsme se zabývali podrobněji grafickými režimy, naučili jsme se, jak zjistit aktuální nastavení, jak zjistit všechny přístupné režimy a jak přepnout do požadovaného režimu. V tomto pokračování ještě zůstaneme u toho, co souvisí s obrazovkou, a také trochu zabrousíme do vzhledu pracovní plochy.
Klepněte pro větší obrázek
 
Spořič obrazovky a úsporný režim

Ukažme si nejprve, jak programově zjistit, zda je spořič obrazovky aktivován, a jaká je nastavená prodleva před jeho spuštěním. K tomu nám poslouží funkce SystemParametersInfo:

BOOL SystemParametersInfo(
  UINT uiAction,  // systemový parametr, který chceme získat nebo nastavit
  UINT uiParam,  // různé podle parametru
  PVOID pvParam,  // různé podle parametru
  UINT fWinIni    // volba zápisu do uživatelského profilu
);

Tato funkce umožňuje získat nebo nastavit mnoho systémových parametrů. Který parametr požadujeme, určíme zadáním příslušné konstanty do parametru uiAction. Podle zadaného parametru uiAction se pak liší význam dalších parametrů. Konkrétně pro zjištění, zda je aktivován spořič obrazovky, zadáme jako uiAction SPI_GETSCREENSAVEACTIVE, pak parametr pvParam je adresa Booleovské proměnné, do které nám sytém naplní výslednou hodnotu: TRUE, pokud je spořič aktivován a naopak. Podobně pro zjištění prodlevy před spuštěním spořiče zadáme jako parametr uiAction SPI_GETSCREENSAVETIMEOUT a parametr pvParam je pak adresa proměnné typu INT, kterou nám funkce naplní hodnotou v sekundách, určující time-out spořiče. Ukažme si to na praktickém příkladě. Ukázkový příklad k tomuto článku je MFC aplikace založená na dialogu. Na tomto dialogu je (mimo jiné) check-box a static-control, ve kterých si zobrazíme výše uvedené získané hodnoty (na stisk tlačítka):

void CUkazkaDlg::OnGetSaverInfo()
{
  BOOL ssActive;
  INT TimeOut;
  SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &ssActive, 0);
  if ( ssActive )
    SendDlgItemMessage(IDC_SAVER_ACTIVE, BM_SETCHECK, BST_CHECKED, 0);
  else
    SendDlgItemMessage(IDC_SAVER_ACTIVE, BM_SETCHECK, BST_UNCHECKED, 0);
  SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &TimeOut, 0);
  SetDlgItemInt(IDC_SAVER_TIMEOUT, TimeOut, FALSE);
}

Nyní si také ukažme, jak některé parametry nastavit. Hodnoty parametru uiAction v tom případě mají obdobný název s tím rozdílem, že začínají na SPI_SETxxxxx. Navíc v případě nastavení parametrů je významný poslední parametr fWinIni, určující další možnosti změny parametrů. Můžeme zadat následující hodnoty:

  • SPIF_UPDATEINIFILE – nové nastavení je zapsáno do uživatelského profilu do registrů, zůstává tedy v platnosti i po restartu systému.
  • SPIF_SENDCHANGE – systém pošle všem hlavním oknům běžících aplikací zprávu WM_SETTINGCHANGE, obsahující informace o této změně v nastavení.
  • SPIF_SENDWININICHANGE – stejný význam jako SPIF_SENDCHANGE.
Aktivace a deaktivace spořiče obrazovky (se zápisem do registru) pak konkrétně vypadá takto:

void CUkazkaDlg::OnDisableSaver()
{
  SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE,
    NULL, SPIF_UPDATEINIFILE);
 
}

void CUkazkaDlg::OnSaverEnable()
{
  SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE,
    NULL, SPIF_UPDATEINIFILE);
}

Jak vidíte, aktivitu určíme Booleovskou hodnotou parametru uiParam.

Podobně si uveďme příklady nastavení prodlevy spořiče. Zde jen podotknu, že programově máme možnost nastavit přesnou hodnotu v sekundách, třeba tedy pouhých 5 sekund, což nám standardní systémový dialog nastavení vlastností obrazovky neumožňuje, zde máme minimální hodnotu 1 minuta a „citlivost“ na celé minuty. Takže nastavení prodlevy na 10 sekund vypadá takto:

void CUkazkaDlg::OnSaverTimeout10()
{
  SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 10,
    NULL, SPIF_UPDATEINIFILE); 
}

Podobně můžeme nastavit prodlevu vypnutí monitoru, resp. jeho přepnutí do úsporného režimu, řekněme na 5 minut:

void CUkazkaDlg::OnPoweroffTimeout5()
{
  SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 5*60,
    NULL, SPIF_UPDATEINIFILE); 
}

Nyní si ukažme, jak programově spustit spořič obrazovky a vypnout monitor. Zejména jednoduchý program na vypnutí monitoru může být užitečný. Optimální nastavení prodlevy je v tomto případě 15 – 20 minut, a pokud uživatel odchází na delší dobu od počítače (třeba na oběd), může tak vypnout monitor okamžitě a nečekat nějakých 20 minut, po nichž by se monitor vypnul sám, a tímto způsobem ušetří pár wattů (a možná minut životnosti obrazovky). Takže jak vypadá konkrétní kód? V tomto případě použijeme zprávu WM_SYSCOMMAND s příslušným parametrem wParam, kterou pošleme nejlépe všem hlavním oknům spuštěných aplikací (jako parametr hwnd určující cílové okno tedy uvedeme konstantu HWND_BROADCAST). Spuštění spořiče obrazovky:

void CUkazkaDlg::OnLaunchSave()
{
  Sleep(500);
  ::SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
}

přepnutí do úsporného režimu:

void CUkazkaDlg::OnMonitorPoweroff()
{
  Sleep(500);
  ::SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, 2);
}

Pokud se ptáte, proč je v obou případech volána funkce Slep, přerušující běh programu (v tomto případě 500ms, tedy půl sekundy), důvod je praktický. Pokud totiž tento příkaz spouštíme kliknutím myší, snadno by se stalo, že by uživatel „zpětným rázem“ myši spuštěný spořič ihned deaktivoval, neboť systém by zachytil po jeho spuštění pohyb myši. Necháme proto uživatele s jeho myší půl sekundy „uležet“ a pak teprve spořič spustíme.

Vzhled pracovní plochy

Nyní se podívejme na pracovní plochu. Ukažme si například, jak programově nastavit tapetu na pracovní plochu. Pokud není zapnut sytém „Aktive Desktop“, tedy aktivní pracovní plocha, můžeme jako tapetu nastavit pouze bitmapu a použijeme opět funkci SystemParametersInfo. Jako parametr uiAction uvedeme SPI_SETDESKWALLPAPER, a parametr pvParam pak určuje jméno souboru s bitmapou:

void CUkazkaDlg::OnSetWallpaperNoad()
{
  SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
    (PVOID)(LPCTSTR)"d:\\data\\pes.bmp", 0);
}

Pokud je však zapnut systém ActiveDesktop, tento způsob nebude fungovat. Musíme pak použít rozhraní IActiveDesktop, přičemž můžeme jako tapetu specifikovat nejen bitmapu, ale třeba i jpg nebo gif soubor. Jak na to? Musíme nejprve inicializovat nebo již mít inicializovanou knihovnu COM, a to pomocí funkce CoInitialize. Pak pomocí funkce CoCreateInstance získáme přístup k rozhraní IActiveDesktop, a nyní již můžeme použít jeho metody, z nichž jedna slouží k nastavení tapety (IActiveDesktop->SetWallpaper):

HRESULT SetWallpaper(
    LPCWSTR pwszWallpaper,
    DWORD dwReserved
);

Nejlépe bude, když si ukážeme konkrétní příklad nastavení tapety, kterou necháme uživatele vybrat standardním otevíracím dialogem:

void CUkazkaDlg::OnSetWallpaper()
{
  CFileDialog openDialog(TRUE);
  if ( openDialog.DoModal() != IDOK )
    return;
  WCHAR name[MAX_PATH];
  MultiByteToWideChar(CP_ACP, 0, openDialog.GetPathName().GetBuffer(_MAX_PATH),
    strlen(openDialog.GetPathName().GetBuffer(_MAX_PATH))+1,
      name, sizeof(name));
  CoInitialize(NULL);
  HRESULT hr;
  IActiveDesktop *pActiveDesktop;

  hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
    IID_IActiveDesktop, (void*>&pActiveDesktop);
  if ( hr != S_OK )
  {
    MessageBox("chyba při CoCreateInstance");
    return;
  }

  if ( pActiveDesktop->SetWallpaper((LPCWSTR)name, 0) != S_OK )
  {
    MessageBox("Chyba SetWallpaper");
    return;
  }
  pActiveDesktop->ApplyChanges(AD_APPLY_ALL);
  pActiveDesktop->Release();
  CoUninitialize();
}

Ještě doplním, že musíte mít includován soubor shlobj.h. V případě MFC aplikace pak v našem příkladě musíme mít tyto vložené soubory:

#include <afxwin.h>        // MFC core and standard components
#include <afxext.h>        // MFC extensions
#include <wininet.h>
#include <afxdisp.h>        // MFC Automation classes
#include <afxdtctl.h>    // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>      // MFC support for Windows Common Controls

Dále můžeme chtít programově nastavit rozvržení tapety, tedy zda má být roztažená na celou plochu, uprostřed nebo „vykachlíkovaná“. Také to nám umožňuje rozhraní IActiveDesktop. Použijeme jeho metodu IActiveDesktop->SetWallpaperOptions

HRESULT SetWallpaperOptions(
    LPCWALLPAPEROPT pwpo,
    DWORD dwReserved
);

kde pwpo je adresa struktury

typedef struct _tagWALLPAPEROPT {
    DWORD dwSize;
    DWORD dwStyle;
} WALLPAPEROPT;

kde parametr dwStyle může nabývat následujících hodnot, jejichž význam je z názvu zřejmý:

  • WPSTYLE_CENTER
  • WPSTYLE_TILE
  • WPSTYLE_STRETCH
  • WPSTYLE_MAX
Konkrétní příklad v naší ukázce načte (na stisknutí tlačítka) výběr z bombo-boxu a podle toho nastaví jednu z možností tapety:

void CUkazkaDlg::OnApplyWallpapStyle()
{
  CoInitialize(NULL);
  HRESULT hr;
  IActiveDesktop *pActiveDesktop;
  hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
    IID_IActiveDesktop, (void*>&pActiveDesktop);
  WALLPAPEROPT wpo;
  wpo.dwSize = sizeof(WALLPAPEROPT);
  LRESULT curSel = SendDlgItemMessage(IDC_WALLPAPER_STYLE,
    CB_GETCURSEL, 0, 0);
  switch ( curSel )
  {
    case 0:
      wpo.dwStyle = WPSTYLE_CENTER;
      break;
    case 1:
      wpo.dwStyle = WPSTYLE_TILE;
      break;
    case 2:
      wpo.dwStyle = WPSTYLE_STRETCH;
      break;
    case 3:
      wpo.dwStyle = WPSTYLE_MAX;
      break;
  }
  pActiveDesktop->SetWallpaperOptions(&wpo, 0);
  pActiveDesktop->ApplyChanges(AD_APPLY_ALL);
  pActiveDesktop->Release();
  CoUninitialize();
}

Přidání položky na Aktivní desktop

Nyní si ještě ukážeme, jak (v případě zapnutého aktivního desktopu) programově přidat položku aktivního desktopu na plochu. Také k tomu samozřejmě použijeme rozhraní IActiveDesktop a jeho metodu AddDesktopItem:

HRESULT AddDesktopItem(
    LPCOMPONENT pcomp,
    DWORD dwReserved
);

kde parametr pomp je adresa struktury, ve které určíme požadované parametry přidané položky aktivního desktopu:

typedef struct _tagCOMPONENT
{
    DWORD dwSize;
    DWORD dwID;
    int iComponentType;
    BOOL fChecked;
    BOOL fDirty;
    BOOL fNoScroll;
    COMPPOS cpPos;
    WCHAR wszFriendlyName[MAX_PATH];
    WCHAR wszSource[INTERNET_MAX_URL_LENGTH];
    WCHAR wszSubscribedURL[INTERNET_MAX_URL_LENGTH];
    DWORD dwCurItemState;
    COMPSTATEINFO csiOriginal;
    COMPSTATEINFO csiRestored;
}
COMPONENT, *LPCOMPONENT;

Nejlepší bude ukázat si konkrétní příklad, jak přidat jako položku aktivního desktopu internetovou stránku umístěnou přímo na Internetu, tedy nikoli uloženou na pevném disku.

void CUkazkaDlg::OnAddDesktopItem()
{
  COMPONENT component;
  COMPPOS comppos;
  CoInitialize(NULL);
  HRESULT hr;
  IActiveDesktop *pActiveDesktop;

  hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
    IID_IActiveDesktop, (void*>&pActiveDesktop);
  ZeroMemory(&component, sizeof(COMPONENT));
  component.dwSize = sizeof(COMPONENT);
  component.iComponentType = COMP_TYPE_WEBSITE;
  component.fChecked = TRUE;
  component.fDirty = TRUE;
  component.fNoScroll = TRUE;
 
  comppos.dwHeight = 600;
  comppos.dwSize = sizeof(COMPPOS);
  comppos.dwWidth = 800;
  comppos.fCanResize = TRUE;
  comppos.fCanResizeX = TRUE;
  comppos.fCanResizeY = TRUE;
  comppos.iLeft = 100;
  comppos.iTop = 20;
  comppos.izIndex = 0;

  component.cpPos = comppos;
  MultiByteToWideChar(CP_ACP, 0, "R+J Software",
    strlen("R+J Software")+1,
      component.wszFriendlyName, sizeof(component.wszFriendlyName));
  MultiByteToWideChar(CP_ACP, 0, "http://www.rplusj.cz",
    strlen("http://www.rplusj.cz")+1,
      component.wszSource, sizeof(component.wszFriendlyName));
  component.dwCurItemState = IS_NORMAL;
  pActiveDesktop->AddDesktopItem(&component, 0);
  pActiveDesktop->ApplyChanges(AD_APPLY_ALL);
  pActiveDesktop->Release();
  CoUninitialize();
}

Změna systémových barev

Tolik v tomto článku k úpravě pracovní plochy a na závěr si ještě ukážeme, jak lze měnit vzhled systému, konkrétně systémově barvy, tedy co má uživatel přístupné v nastavení obrazovky na záložce „vzhled“ jako jednotlivé položky. Jako příklad si uvedeme změnu barvy pracovní plochy (když už jsme se jí tak zabývali…). K tomu nám poslouží funkce SetSysColors:

BOOL WINAPI SetSysColors(
  int cElements,                // počet prvků
  CONST INT *lpaElements,        // prvky
  CONST COLORREF *lpaRgbValues  // RGB hodnoty
);

Touto funkcí můžeme „naráz“ změnit více systémových barev, proto parametr cElements, určující počet prvků a další parametry představující pole příslušných hodnot. V našem případě zůstaneme u jedné barvy, konkrétně barvy pracovní plochy, určené konstantou COLOR_DESKTOP. V našem případě nabídneme uživateli standardní systémový dialog výběru barvy a vybranou barvu pak nastavíme jako barvu pracovní plochy:

void CUkazkaDlg::OnSetSysColor()
{
  CColorDialog colorDialog;
  if ( colorDialog.DoModal() != IDOK )
    return;
  int aiElements[1] = {COLOR_DESKTOP};
  DWORD aColors[1];
  aColors[0] = colorDialog.GetColor();
  SetSysColors(1, aiElements, aColors);
}

Změna systémových kurzorů

Na úplný závěr ještě jednu věc týkající se také „vzhledu“. Ukážeme si, jak můžeme zaměnit libovolný ze systémových kurzorů nějakým vlastním. K tomuto účelu používáme funkci SetSystemCursor:

BOOL SetSystemCursor (
  HCURSOR hcur,  // handle kurzoru
  DWORD id      // identifikátor systémového kurzoru
);

Parametr id určuje, který kurzor ze systémového schématu chceme změnit. Může nabývat jedné z předdefinovaných hodnot (začínajících OCR_xxx). K tomu jednu důležitou poznámku: Abychom mohli tyto hodnoty používat, musíme definovat hodnotu OEMRESOURCE, a to „někde“ před tím, než vložíme soubor <windows.h>. Konkrétně může hlavičkový soubor vypadat takto (soubor windows.h je v MFC aplikaci obsažen v hlavičkovém souboru knihovny MFC, tedy afxwin.h):

// ….
#define OEMRESOURCE

#include <afxwin.h>        // MFC core and standard components
#include <afxext.h>        // MFC extensions
// …. Pokrač.

Jako příklad si uveďme změnu standardního kurzoru, tedy OCR_NORMAL na náš vlastní kurzor, který si načteme ze zdrojů aplikace:

void CUkazkaDlg::OnSetSystemCursor()
{
  SetSystemCursor(LoadCursor(AfxGetInstanceHandle(),
    MAKEINTRESOURCE(IDC_CURSOR1)),
    OCR_NORMAL);
}

Zde si můžete stáhnout ukázkový projekt display_II.zip.

Váš názor Další článek: USB 2.0 a Bluetooth do Windows XP

Témata článku: Software, Windows, Programování, Internet Explorer, Pracovní plocha, Code, Ukázkový příklad, Obrazovka, Aktivní uživatel, Parametr, PVP, Plocha, Následující minuta, HR, DWS, Timeout, PACT


Určitě si přečtěte

Co je to UWB? Nová technologie zastoupí Wi-Fi, Bluetooth i NFC a slibuje velké věci

Co je to UWB? Nová technologie zastoupí Wi-Fi, Bluetooth i NFC a slibuje velké věci

** V nových mobilech se začíná objevovat tajemná zkratka UWB ** Jde o další technologii, jak navzájem propojit různá zařízení ** Oproti Wi-Fi a Bluetooth má řadu výhod

Lukáš Václavík | 36

Lukáš Václavík
UWBIoTTechnologie
Dostali jste nový počítač? Tohle s ním udělejte, než ho začnete používat

Dostali jste nový počítač? Tohle s ním udělejte, než ho začnete používat

** Každý nový počítač si zaslouží počáteční péči ** Odinstalujte bloatware a nezapomeňte na vhodné nastavení ** Poradíme, jak se o počítač s Windows 10 postarat

David Polesný, Stanislav Janů | 71

David PolesnýStanislav Janů
PočítačeNotebooky
Nejlepší notebooky do 20 000 Kč. Tipy, co se dnes vyplatí koupit

Nejlepší notebooky do 20 000 Kč. Tipy, co se dnes vyplatí koupit

** S cenou do 20 tisíc lze vybrat solidní notebook na práci i hry ** Přenosné notebooky nabídnou i kovová těla a rychlý hardware ** Možná největší problém je nedostupnost, nejžádanější kusy jsou vyprodané

David Polesný | 33

David Polesný
VánoceNotebooky
CZ.NIC bezplatně naděluje USB/NFC klíče. Jak jej získat?
Lukáš Václavík
CZ.NICeGovernment
WhatsApp konečně umožní smazat velké soubory z konverzací, aby nezabíraly místo
Vladislav Kluska
WhatsAppFacebookInstant Messaging
Zapomeňte na destičky. Raspberry Pi 400 je nový počítač zabudovaný do klávesnice
Lukáš Václavík
Raspberry PiPočítače
Elon Musk podpořil Signal jako náhradu WhatsAppu. Aplikaci okamžitě zavalili uživatelé
Markéta Mikešová
WhatsAppElon MuskFacebook

Aktuální číslo časopisu Computer

Jak prodloužit výdrž notebooku

Velké testy: gamepady a inkoustové tiskárny

Důkladný test Sony Playstation 5