Работа с селекторными кнопками




 

В этом разделе описываются селекторные кнопки* (radio buttons), использующиеся для представления в окне множества опций, из которых можно выбрать только одну. Селекторная кнопка состоит из небольшой круглой кнопки и текста с описанием селекторной кнопки. Если кнопка заполнена, опция установлена, если нет – опция сброшена. Windows поддерживает два типа селекторных кнопок – устанавливаемые вручную (ручные) и автоматические. Ручные селекторные кнопки (как и ручные контрольные переключатели) требуют, чтобы все действия по управлению ими выполняла программа. Управление автоматическими селекторными кнопками выполняет сама Windows. Поскольку управление селекторными кнопками более сложно, чем управ­ление контрольными переключателями, и поскольку автоматические селекторные кноп­ки используются наиболее часто, рассмотрим только этот тип селекторных кнопок.

Как и другие элементы управления, селекторные кнопки описываются в файле ресурсов при определении диалога. Для создания автоматических селекторных кно­пок используется оператор AUTORADIOBUTTON:

 

AUTORADIOBUTTON "строка", ID, X, Y,

Width, Height[,стиль]

 

Здесь "строка" задает текст, a ID – идентификатор селекторной кнопки. Коорди­наты верхнего левого угла задаются параметрами X и Y, a ширина и высота – параметрами Width и Height. Стиль задает вид селекторной кнопки. Если этот параметр не указан, стиль устанавливается по умолчанию, то есть строка отображается справа от маленькой кнопки и пользователь может переключаться к селекторной кнопке с помощью клавиши [Tab].

Как уже упоминалось, селекторные кнопки используются для представления группы опций, из которых можно выбрать только одну. Если в такой группе используются автоматические селекторные кнопки, Windows управляет ими таким образом, чтобы в каждый момент времени была выбрана только одна из них. То есть, если пользователь выбирает одну из селекторных кнопок, ранее выбранная кнопка автоматически очи­щается, и поэтому невозможно выбрать более одной селекторной кнопки одновременно.

Селекторная кнопка (в том числе и автоматическая) может быть установлена в нужное состояние программно, если направить ей сообщение BM_SETCHECK, используя функцию API SendDlgItemMessage(). Значение wParam при этом опреде­ляет будущее состояние кнопки: если оно равно 1, то кнопка выбрана, если 0 – то нет. По умолчанию все кнопки изначально очищены.

С помощью функции SendDlgItemMessage() можно выбрать более одной селек­торной кнопки одновременно либо сбросить все селекторные кнопки. Однако нормальный стиль использования селекторных кнопок в Windows предполагает, что в каждый момент времени может быть выбрана одна, и только одна, селекторная кнопка. Нарушать это правило не рекомендуется.

Состояние селекторной кнопки можно определить при помощи сообщения BM_GETCHECK. Если при этом селекторная кнопка возвращает 1, она выбрана, а если 0 – нет.

Чтобы включить селекторные кнопки в пример программы, добавьте в файл ресурсов определения диалога следующие строки. Заметьте, что при этом добавляется еще одна рамка группы для селекторных кнопок. Это, конечно, не обязательно, однако в диалогах Windows выделение групп элементов является общепринятым.

 

GROUPBOX "Селекторы", ID_GT2, 62, 1, 53, 34

AUTORADIOBUTTON "Селектор 1", ID_RB1, 64, 10, 50, 12

AUTORADIOBUTTON "Селектор 2", ID_RB2, 64, 22, 50, 12

 

Пример 7-4. Ниже приводится измененный текст программы предыдущего примера, в кото­ром добавлен фрагмент работы с двумя селекторными кнопками. Поскольку эти кнопки автоматические, изменений в программе немного. Заметьте, что состояние селекторных кнопок сохраняется во внешних переменных rstatus1 и rstatus2. Значе­ния этих переменных используются и для установки состояний селекторных кнопок при активизации диалога, и для отображения их состояния по команде меню Статус.

 

// Демонстрация селекторных переключателей

// (радиокнопок)

 

#include <Windows.h>

#include <String.h>

#include <Stdio.h>

#include "Mydialog.h"

 

LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);

BOOL CALLBACK DialogFunc(HWND,UINT,WPARAM,LPARAM);

char szWinName[]="МоеОкно"; // Имя класса окна

HINSTANCE hInst;

int cbstatus1=0; // Для хранения состояния

int cbstatus2=0; // контрольных переключателей

int rbstatus1=0; // Для хранения состояния

int rbstatus2=0; // селекторных кнопок

 

int WINAPI WinMain(HINSTANCE hThisInst,

HINSTANCE hPrevInst,

LPSTR lpszArgs,

int nWinMode)

{

HWND hwnd;

MSG msg;

WNDCLASS wcl;

HACCEL hAccel;

// Определить класс окна

wcl.hInstance=hThisInst; // Дескриптор приложения

wcl.lpszClassName=szWinName; // Имя класса окна

wcl.lpfnWndProc=WindowFunc; // Функция окна

wcl.style=0; // Стиль по умолчанию

wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка

wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор

wcl.lpszMenuName="MYMENU"; // Меню

wcl.cbClsExtra=0; // Без дополнительной

wcl.cbWndExtra=0; // информации

wcl.hbrBackground= // Белый фон

(HBRUSH)GetStockObject(WHITE_BRUSH);

if(!RegisterClass(&wcl)) // Зарегистр. класс окна

return 0;

hwnd=CreateWindow(szWinName, // Создать окно

"Работа с селекторными кнопками",

WS_OVERLAPPEDWINDOW, // Стиль

CW_USEDEFAULT, // Х-координата

CW_USEDEFAULT, // Y-координата

CW_USEDEFAULT, // Ширина

CW_USEDEFAULT, // Высота

HWND_DESKTOP, // Нет родит. окна

NULL, // Нет меню

hThisInst, // Дескрип. приложения

NULL); // Без дополн. аргументов

hInst=hThisInst; // Дескрип. текущ. приложения

// Загрузить акселераторы

hAccel=LoadAccelerators(hThisInst,"MYMENU");

ShowWindow(hwnd,nWinMode); // Показать окно

UpdateWindow(hwnd); // Перерисовать содержимое

while(GetMessage(&msg,NULL,0,0))

{ // Запустить цикл обработки сообщений

if(!TranslateAccelerator(hwnd,hAccel,&msg))

{

TranslateMessage(&msg); // Исп. клавиатуры

DispatchMessage (&msg); // Возврат к Windows

}

}

return msg.wParam;

}

 

// Следующая функция вызывается операционной системой

// Windows и получает в качестве параметров сообщения

// из очереди сообщений данного приложения

 

LRESULT CALLBACK WindowFunc(HWND hwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

char str[255];

switch(message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_DIALOG1:

DialogBox(hInst,"MYDB",

hwnd,DialogFunc);

break;

case ID_STATUS: // Состояние переключат.

if(cbstatus1)

strcpy(str,

"Переключатель 1 выбран\n");

else

strcpy(str,

"Переключатель 1 не выбран\n");

if(cbstatus2)

strcat(str,

"Переключатель 2 выбран\n");

else

strcat(str,

"Переключатель 2 не выбран\n");

if(rbstatus1)

strcat(str,

"Селектор 1 выбран\n");

else

strcat(str,

"Селектор 1 не выбран\n");

if(rbstatus2)

strcat(str,

"Селектор 2 выбран\n");

else

strcat(str,

"Селектор 2 не выбран\n");

MessageBox(hwnd,str,"",MB_OK);

break;

case IDM_HELP:

MessageBox(hwnd,"Помощь","",MB_OK);

break;

}

break;

case WM_DESTROY: // Завершение программы

PostQuitMessage(0);

break;

default:

// Все сообщения, не обрабатываемые в данной

// функции, направляются на обработку по

// умолчанию

return DefWindowProc(hwnd,message,

wParam,lParam);

}

return 0;

}

 

// Простая функция диалога

BOOL CALLBACK DialogFunc(HWND hdwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

switch(message)

{

case WM_INITDIALOG: // Инициализация диалога;

// установить состояние

// контрольн. переключателей

// и селектторных кнопок

SendDlgItemMessage(hdwnd,ID_CB1,

BM_SETCHECK,cbstatus1,0);

SendDlgItemMessage(hdwnd,ID_CB2,

BM_SETCHECK,cbstatus2,0);

SendDlgItemMessage(hdwnd,ID_RB1,

BM_SETCHECK,rbstatus1,0);

SendDlgItemMessage(hdwnd,ID_RB2,

BM_SETCHECK,rbstatus2,0);

return 1;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDCANCEL:

EndDialog(hdwnd,0);

return 1;

case IDOK:

// Обновить значения переменных,

// содержащих статус переключателей

cbstatus1=SendDlgItemMessage

(hdwnd,ID_CB1,

BM_GETCHECK,0,0);

// Выбран ли переключатель?

cbstatus2=SendDlgItemMessage

(hdwnd,ID_CB2,

BM_GETCHECK,0,0);

// Выбран ли переключатель?

// Обновить значения переменных,

// содержащих статус селекторных кнопок

rbstatus1=SendDlgItemMessage

(hdwnd,ID_RB1,

BM_GETCHECK,0,0);

// Выбран ли селектор?

rbstatus2=SendDlgItemMessage

(hdwnd,ID_RB2,

BM_GETCHECK,0,0);

// Выбран ли селектор?

EndDialog(hdwnd,0);

return 1;

case ID_CB1:

// Это ручной переключатель

// Пользователь его выбрал

// Поэтому нужно изменить его состояние

if(!SendDlgItemMessage(hdwnd,ID_CB1,

BM_GETCHECK,0,0))

SendDlgItemMessage(hdwnd,ID_CB1,

BM_SETCHECK,1,0);

else // Очистить его

SendDlgItemMessage(hdwnd,ID_CB1,

BM_SETCHECK,0,0);

return 1;

}

}

return 0;

}

 

Диалог, создаваемый этой программой, будет выглядеть так, как показано на рис. 7.3.

 

Линейки прокрутки

 

В заключении главы рассмотрим еще один элемент управления – линейку прокрутки (scroll bar). В Windows существует два варианта использования линеек прокрутки. Первый, когда линейка прокрутки может функционировать как часть обычного окна или диалога. Второй, когда она может действовать самостоятельно, как и любой другой элемент управления. Хотя в обоих вариантах управление линейкой прокрутки осуществляется одним и тем же способом, использование линейки прокрутки как элемента управления требует применения некоторых специальных приемов. По этой причине в данном разделе мы рассмотрим использование линейки прокрутки как отдельного элемента управления.

 

 

Рис. 7.3. Диалог с селекторными кнопками

 

Для того чтобы добавить линейку прокрутки в диалог, используется оператор SCROLLBAR, имеющий следующую общую форму:

 

SCROLLBAR ID, X, Y, Width, Height[, стиль]

 

Здесь ID – идентификатор линейки прокрутки, Х и Y – координаты ее верхнего левого угла, a Width и Height – размеры соответственно по горизонтали и вертикали. Стиль определяет вид и форму линейки прокрутки. По умолчанию выбирается стиль SBS_HORZ, который определяет горизонтальную линейку прокрутки. Для создания вертикальной линейки прокрутки необходимо задать стиль SBS_VERT. Чтобы линей­ка прокрутки могла получать фокус и реагировать на ввод с клавиатуры, следует добавить стиль VS_TABSTOP. Ниже приведен пример оператора создания верти­кальной линейки прокрутки:

 

SCROLLBAR ID_SB1, 130, 10, 10, 70,

SBS_VERT|WS_TABSTOP

 

Сообщения линейки прокрутки. В отличие от других элементов управления линейки прокрутки не генерируют сообщения WM_COMMAND. Вместо него линейки прокрутки – независимо от того, являются ли они частью окна или отдельными элементами управления – генерируют либо WM_HSCROLL, либо WM_VSCROLL для горизонтальных и вертикальных линеек соответственно. При этом младшее слово wParam содержит код, который определяет действие, выполненное над линейкой прокрутки, alParam – дескриптор линейки прокрутки. Для линеек прокрутки, являющихся частью окна, lParam равен 0.

Как уже упоминалось, LOWORD(wParam) содержит код действия, произведен­ного над линейкой прокрутки. Ниже перечислены некоторые типы таких действий:

SB_LINEUP

SB_LINEDOWN

SB_PAGEUP

SB_PAGEDOWN

SB_THUMBPOSITION

SB_THUMBTRACK

 

При изменении состояния линейки прокрутки на один шаг прокрутки в программу посылается один из кодов: SB_LINEUP или SB_LINEDOWN. Коды SB_PAGEUP и SB_PAGEDOWN используются при изменении состояния линейки прокрутки на страницу вверх или вниз. Код SB_THUMBPOSITION передается при изменении позиции слайдера (бегунка – подвижного элемента линейки прокрутки), а код SB_THUMBTRACK – при его перемещении. Это позволяет отслеживать перемеще­ние слайдера и реагировать на этот процесс. При посылке кодов SB_THUMBPOSITION и SB_THUMBTRACK старшее слово параметра wParam содержит текущую позицию слайдера.

 

Установка диапазона прокрутки. Перед тем, как использовать линейку, необходимо установить для нее диапазон прокрутки, который определяет количество шагов прокрутки между крайними пози­циями слайдера. По умолчанию линейки прокрутки, использующиеся как часть окна, имеют диапазон от 0 до 100, линейки же, использующиеся как элементы управления, — от 0 до 0, поэтому для таких линеек нужно сначала явно задать диапазон прокрутки. С этой целью используется функция API SetScrollRange():

 

BOOL SetScrollRange(HWND hwnd, int which, int min,

int max, BOOL repaint);

 

Здесь hwnd – дескриптор, идентифицирующий линейку прокрутки. Для линеек прокрутки, использующихся как часть окна, hwnd должен быть дескриптором этого окна, а для элементов управления – дескриптором самого элемента. (Вспомните, линейки прокрутки передают свои дескрипторы в lParam.) Параметр which задает тип линейки прокрутки, для которой задается диапазон. Если линейки прокрутки исполь­зуются как часть окна, для вертикальных линеек этот параметр должен равняться SB_VERT, а для горизонтальных – SB_HORZ. Для лийеек прокрутки, используемых как элементы управления, этот параметр должен быть SB_CTL. Значения min и max определяют диапазон прокрутки и могут задаваться в пределах от 0 до 32767. Значение параметра repaint определяет, должна ли линейка прокрутки перерисовываться при установке диапазона. Если он равен TRUE, то после установки диапазона линейка прокрутки перерисовывается, а если FALSE – перерисовка не выполняется. Функ­ция возвращает ненулевое значение при успешном завершении и нуль при возник­новении ошибки.

 

Установка позиции слайдера на линейке прокрутки. Линейки прокрутки всегда управляются программой. Поэтому Ваша программа должна при необходимости самостоятельно устанавливать позицию слайдера. Для этого используется функция API SetScrollPos(), прототип которой имеет следующий вид:

 

int SetScrollPos(HWND hwnd, int which, int pos,

BOOL repaint);

 

Здесь hwnd – дескриптор, идентифицирующий линейку прокрутки. Для линеек прокрутки, использующихся как часть окна, hwnd должен быть дескриптором этого окна, а для элементов управления – дескриптором этой линейки. Значение which определяет тип линейки прокрутки, для которой устанавливается позиция слайдера. В случае, если линейка прокрутки используется как часть окна, этот параметр должен быть SB_VERT или SB_HORZ для вертикальной или горизонтальной линейки соответственно. Для линеек прокрутки, используемых как элементы управления, этот параметр должен быть SB_CTL. Значение pos определяет позицию слайдера, которая должна быть установлена, и должно быть задано в пределах установленного диапа­зона прокрутки. Параметр repaint определяет, должна ли линейка прокрутки быть перерисована после установки позиции слайдера. Если он равен TRUE, то линейка прокрутки будет перерисована, а если FALSE, то нет.

 

Пример 7-5. Ниже приводится небольшая программа создания линейки прокрутки и обработ­ки ее сообщений. Для этой программы необходим следующий файл ресурсов:

 

// Демонстрация линейки прокрутки

#include <Windows.h>

#include "Scroll.h"

MYMENU MENU

{

MENUITEM "&Прокрутка", IDM_DIALOG1

MENUITEM "Помощь", IDM_HELP

}

MYMENU ACCELERATORS

{

VK_F1, IDM_HELP, VIRTKEY

VK_F2, IDM_DIALOG1, VIRTKEY

}

MYDB DIALOG 18, 18, 142, 92

CAPTION "Работа с прокруткой"

STYLE DS_MODALFRAME|WS_POPUP|WS_CAPTION|WS_SYSMENU

{

GROUPBOX "Позиция слайдера",ID_GB1, 1, 1, 72, 30

SCROLLBAR ID_SB1, 130, 10, 10, 70,

SBS_VERT|WS_TABSTOP

}

Нужно также создать файл определений Sscroll.h:

 

#define IDM_DIALOG1 100

#define IDM_HELP 101

#define ID_SB1 102

#define ID_GB1 103

 

Ниже приводится текст программы работы с линейкой прокрутки. Эта программа обрабатывает сообщения SB_LINEUP, SB_LINEDOWN, SB_PAGEUP, SB_PAGE-DOWN,SB_THUMBPOSITION и SB_THUMBTRACK в соответствии с перемеще­ниями слайдера. Текущая позиция слайдера отображается в группе Позиция слайдера. Отображаемое значение тем или иным способом будет изменяться при перемещении слайдера.

 

// Демонстрация линейки прокрутки

#include <Windows.h>

#include <String.h>

#include <Stdio.h>

#include "Scroll.h"

#define RANGEMAX 50

LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);

BOOL CALLBACK DialogFunc(HWND,UINT,WPARAM,LPARAM);

char szWinName[]="МоеОкно"; // Имя класса окна

HINSTANCE hInst;

 

int WINAPI WinMain(HINSTANCE hThisInst,

HINSTANCE hPrevInst,

LPSTR lpszArgs,

int nWinMode)

{

HWND hwnd;

MSG msg;

WNDCLASS wcl;

HACCEL hAccel;

// Определить класс окна

wcl.hInstance=hThisInst; // Дескриптор приложения

wcl.lpszClassName=szWinName; // Имя класса окна

wcl.lpfnWndProc=WindowFunc; // Функция окна

wcl.style=0; // Стиль по умолчанию

wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка

wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор

wcl.lpszMenuName="MYMENU"; // Меню

wcl.cbClsExtra=0; // Без дополнительной

wcl.cbWndExtra=0; // информации

wcl.hbrBackground= // Белый фон

(HBRUSH)GetStockObject(WHITE_BRUSH);

if(!RegisterClass(&wcl)) // Зарегистр. класс окна

return 0;

hwnd=CreateWindow(szWinName, // Теперь создать окно

"Линейка прокрутки",

WS_OVERLAPPEDWINDOW, // Стиль

CW_USEDEFAULT, // Х-координата

CW_USEDEFAULT, // Y-координата

CW_USEDEFAULT, // Ширина

CW_USEDEFAULT, // Высота

HWND_DESKTOP, // Нет родит. окна

NULL, // Нет меню

hThisInst, // Дескрип. приложения

NULL); // Без дополн. аргументов

hInst=hThisInst; // Дескрип. текущ. приложения

// Загрузить акселераторы

hAccel=LoadAccelerators(hThisInst,"MYMENU");

ShowWindow(hwnd,nWinMode); // Показать окно

UpdateWindow(hwnd); // Перерисовать содержимое

while(GetMessage(&msg,NULL,0,0))

{ // Запустить цикл обработки сообщений

if(!TranslateAccelerator(hwnd,hAccel,&msg))

{

TranslateMessage(&msg); // Исп. клавиатуры

DispatchMessage (&msg); // Возврат к Windows

}

}

return msg.wParam;

}

 

// Следующая функция вызывается операционной системой

// Windows и получает в качестве параметров сообщения

// из очереди сообщений данного приложения

 

LRESULT CALLBACK WindowFunc(HWND hwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

switch(message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDM_DIALOG1:

DialogBox(hInst,"MYDB",

hwnd,DialogFunc);

break;

case IDM_HELP:

MessageBox(hwnd,"Помощь","",MB_OK);

break;

}

break;

case WM_DESTROY: // Завершение программы

PostQuitMessage(0);

break;

default:

// Все сообщения, не обрабатываемые в данной

// функции, направляются на обработку по

// умолчанию

return DefWindowProc(hwnd,message,

wParam,lParam);

}

return 0;

}

 

// Простая функция диалога

BOOL CALLBACK DialogFunc(HWND hdwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

char str[255];

static int pos=0;

HDC hdc;

switch(message)

{

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDCANCEL:

EndDialog(hdwnd,0);

return 1;

}

break;

case WM_VSCROLL:

SetScrollRange((HWND)lParam, SB_CTL, 0,

RANGEMAX, 1);

switch(LOWORD(wParam))

{

case SB_LINEDOWN:

pos++;

if(pos > RANGEMAX)

pos=RANGEMAX;

SetScrollPos((HWND)lParam, SB_CTL,

pos, 1);

hdc=GetDC(hdwnd);

sprintf(str, "%d", pos);

TextOut(hdc, 55, 30, " ", 4);

TextOut(hdc, 55, 30, str, strlen(str));

ReleaseDC(hdwnd, hdc);

return 1;

case SB_LINEUP:

pos--;

if(pos < 0)

pos=0;

SetScrollPos((HWND)lParam, SB_CTL,

pos, 1);

hdc=GetDC(hdwnd);

sprintf(str, "%d", pos);

TextOut(hdc, 55, 30, " ", 4);

TextOut(hdc, 55, 30, str, strlen(str));

ReleaseDC(hdwnd, hdc);

return 1;

case SB_THUMBPOSITION:

pos=HIWORD(wParam); // Текущая позиция

SetScrollPos((HWND)lParam, SB_CTL,

pos, 1);

hdc=GetDC(hdwnd);

sprintf(str, "%d", pos);

TextOut(hdc, 55, 30, " ", 4);

TextOut(hdc, 55, 30, str, strlen(str));

ReleaseDC(hdwnd, hdc);

return 1;

case SB_THUMBTRACK:

pos=HIWORD(wParam); // Текущая позиция

SetScrollPos((HWND)lParam, SB_CTL,

pos, 1);

hdc=GetDC(hdwnd);

sprintf(str, "%d", pos);

TextOut(hdc, 55, 30, " ", 4);

TextOut(hdc, 55, 30, str, strlen(str));

ReleaseDC(hdwnd, hdc);

return 1;

case SB_PAGEDOWN:

pos += 5;

if(pos > RANGEMAX)

pos=RANGEMAX;

SetScrollPos((HWND)lParam, SB_CTL,

pos, 1);

hdc=GetDC(hdwnd);

sprintf(str, "%d", pos);

TextOut(hdc, 55, 30, " ", 4);

TextOut(hdc, 55, 30, str, strlen(str));

ReleaseDC(hdwnd, hdc);

return 1;

case SB_PAGEUP:

pos -= 5;

if(pos < 0)

pos= 0;

SetScrollPos((HWND)lParam, SB_CTL,

pos, 1);

hdc=GetDC(hdwnd);

sprintf(str, "%d", pos);

TextOut(hdc, 55, 30, " ", 4);

TextOut(hdc, 55, 30, str, strlen(str));

ReleaseDC(hdwnd, hdc);

return 1;

}

}

return 0;

 

 

}

Рис. 7.4. Окно диалога с линейкой прокрутки

 


На рис. 7.4 представлен результат работы этой программы. Заметьте, что позиция слайдера отображается путем вывода текста в рабочую область окна диалога при помощи вызова TextOut(). Хотя диалог и является окном специального типа, он остается окном, с которым можно делать почти все то же, что и с главным окном.

Многие начинающие Windows-программисты часто считают, что линейки про­крутки использовать сложно. На самом деле линейка прокрутки является одним из простейших элементов управления в Windows.

В следующей главе более подробно изложены вопросы, связанные с выводом в окне текстовых строк.

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-03-31 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: