Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.53/307: Рейтинг темы: голосов - 307, средняя оценка - 4.53
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33187 / 21484 / 8232
Регистрация: 22.10.2011
Сообщений: 36,859
Записей в блоге: 12

Создание форм авторизации и заставки (Splash-формы) в приложениях

05.12.2015, 15:33. Показов 71135. Ответов 1
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Создание формы для авторизации в приложении.

Очень многие делают это совершенно неправильно: уже после того, как написано приложение добавляют еще одну форму, и хотят сделать так, чтобы сначала открывалась новая форма, а потом, когда пользователь введет пароль для входа в программу, скрыть ее и уже продолжать создавать формы как и раньше, до добавления формы авторизации. Это в корне неправильный подход. По нескольким причинам:
  1. Если при таком решении форма авторизации будет назначена главной формой приложения, ее потом нельзя будет закрыть, можно будет только скрыть, иначе при закрытии главной формы будет автоматически закрыто само приложение
  2. Главная (и все остальные) форма приложения вообще не должны создаваться до тех пор, пока пользователь не подтвердит своих прав на использование данного продукта. Иначе очень просто будет чуть более продвинутому пользователю показать уже созданную, но скрытую форму, чем если бы ее вообще еще не существовало

Что же делать в таком случае, как правильно показать форму авторизации, не дать остальным формам создаваться, пока пользователь не войдет с правильным паролем, и при этом не держать эту форму постоянно скрытой в памяти, а сразу после того, как она перестала быть необходимой - закрыть ее.

Решение очень простое: создаем форму авторизации, убираем ее из списка автоматически создаваемых (Project -> Options -> Forms, перенести форму из списка Auto-create в список Available)

На форме расположим 2 поля ввода (edUser для ввода логина и edPass для ввода пароля) и 2 кнопки (btnLogIn для подтверждения и btnCancel для отмены авторизации)

По нажатию на кнопку LogIn на форме авторизации либо просто проверяем соответствие пары логин/пароль:
C++
1
2
3
4
5
6
7
8
9
10
11
void __fastcall TForm3::Button1Click(TObject *Sender)
{
    if (edUser->Text == "volvo" && edPass->Text == "test")
    {
        ModalResult = mrOk; // в случае соответствия возвращаем один результат
    }
    else
    {
        ModalResult = mrCancel; // иначе - другой. Этот же результат - и по нажатию на кнопку Cancel
    }
}
, либо делаем чуть более интересно: пару логин/хеш пароля храним в Ini-файле, и при нажатии на LogIn проверяем соответствие:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __fastcall TForm3::Button1Click(TObject *Sender)
{
    std::auto_ptr<TIniFile> ini (new TIniFile(ChangeFileExt(ParamStr(0), ".ini"))); // #include <IniFiles.hpp>
    std::auto_ptr<TIdHashMessageDigest5> hash(new TIdHashMessageDigest5); // #include <IdHashMessageDigest.hpp>
 
    if(ini->ReadString("users", edUser->Text, "") == hash->HashStringAsHex(edPass->Text, TIdTextEncoding::Default))
    {
        ModalResult = mrOk;
    }
    else
    {
        ModalResult = mrCancel;
    }
}
Разумеется, можно придумать еще много способов хранения паролей или их хешей, но основная идея этого поста - дать общее понимание того, что же делать с этой формой дальше, как ее показать, чтобы только после успешной аутентификации выполнение программы шло дальше.

Для этого в класс формы авторизации нужно добавить статический метод Execute:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TForm3 : public TForm
{
__published:    // IDE-managed Components
    // ...
private:    // User declarations
public:     // User declarations
    __fastcall TForm3(TComponent* Owner);
    static bool __fastcall Execute(); // <--- Вот его описание
};
 
// а вот - реализация:
bool __fastcall TForm3::Execute()
{
    TForm3 *frm = new TForm3(0);
    int res = frm->ShowModal();
    delete frm;
    return res == mrOk; // вернуть признак успешной авторизации
}
А теперь открываем главный файл проекта (Project -> View source), и меняем порядок создания форм с того, что было раньше:
C++
1
2
3
4
5
6
         Application->Initialize();
         Application->MainFormOnTaskBar = true;
 
         Application->CreateForm(__classid(TForm1), &Form1);
         Application->CreateForm(__classid(TForm2), &Form2);
         Application->Run();
на такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        if(TForm3::Execute()) // сначала показываем форму авторизации
        {
            // и только если результат авторизации успешен - создаем главную форму приложения
            Application->Initialize();
            Application->MainFormOnTaskBar = true;
            Application->CreateForm(__classid(TForm1), &Form1);
            Application->Run();
        }
        else
        {
            // иначе показываем сообщение о невозможности войти в программу,
            // и приложение завершается, не создавая никаких форм
            Application->MessageBox(
                _T("Вы не можете пользоваться приложением, так как не прошли авторизацию"),
                _T("Защита приложения")
            );
        }
Это самый простой метод авторизации, когда пользователь просто вводи свой логин/пароль, и в случае, если он ввел их правильно, он получает возможность использовать приложение. Чуть более интересно будет добиться того, чтобы в приложении было несколько групп пользователей, скажем, админ и просто пользователь. Тут тоже есть несколько вариантов реализации:
  1. Сделать одну форму, на которой в зависимости от некоего глобального флажка динамически создавать набор компонентов, нужный для представителя группы пользователей, к которой принадлежит залогинившийся (способ очень хорош тем, что на форме оказываются только необходимые данной группе пользователей компоненты, но для сложных форм с большим количеством компонентов на них создавать все динамически может быть долго по времени)
  2. Все так же сделать одну форму, но уже в дизайнере набросать на нее две группы компонентов (например, на разные вкладки TPageControl, или на разные TPanel), и по значению того же глобального флажка показывать одну вкладку (панель), и скрывать все остальные (этот способ гораздо проще, но теперь на форме, хоть и скрытыми, одновременно присутствуют все компоненты для всех групп пользователей, и все обработчики событий)
  3. Сделать разные формы для разных групп пользователей и создавать/показывать только нужную, остальные вообще не создавать.

Вариант №3 - самый оптимальный. Для его реализации нужно чуть-чуть изменить описание класса формы авторизации:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enum AuthStatus {authNone, authUser, authAdmin}; // это список всех возможных групп пользователей
 
class TForm3 : public TForm
{
__published:    // IDE-managed Components
    TLabeledEdit *edUser;
    TLabeledEdit *edPass;
    TButton *btnLogin;
    TButton *btnCancel;
    void __fastcall btnCancelClick(TObject *Sender);
    void __fastcall btnLoginClick(TObject *Sender);
private:    // User declarations
public:     // User declarations
    __fastcall TForm3(TComponent* Owner);
    static AuthStatus __fastcall Execute();
    static AuthStatus status; // Добавляем флажок
 
};
AuthStatus TForm3::status = authNone; // инициализация статического поля класса
и реализацию обработчика клика по кнопке и метода Execute() :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void __fastcall TForm3::btnLoginClick(TObject *Sender)
{
    // разумеется, тут точно так же можно сделать проверку паролей
    // из INI-файла, только тогда в файле придется еще хранить
    // роль каждого пользователя в системе
    if (edUser->Text == "volvo" && edPass->Text == "test")
    {
        status = authAdmin;
        ModalResult = mrOk;
    }
    else
    if (edUser->Text == "nata" && edPass->Text == "second")
    {
        status = authUser;
        ModalResult = mrOk;
    }
    else
    {
        ModalResult = mrCancel;
    }
}
 
// ---------------------------------------------------------------------------
AuthStatus __fastcall TForm3::Execute()
{
    TForm3 *frm = new TForm3(0);
    TForm3::status = authNone;
    frm->ShowModal();
    delete frm;
    return TForm3::status; // Возвращаем статус пользователя
}
, и изменить главный файл приложения:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
        AuthStatus st = TForm3::Execute(); // получаем статус пользователя
        if (st != authNone) // если авторизация была успешной
        {
            Application->Initialize();
            Application->MainFormOnTaskBar = true;
            switch (st)
            {
            case authAdmin: // залогинился админ - создаем админскую форму
                Application->CreateForm(__classid(TForm1), &Form1);
                // тут можно создать еще формы, которые нужны только админу
                break;
            case authUser: // простой пользователь - создаем пользовательскую
                Application->CreateForm(__classid(TForm2), &Form2);
                // те формы, которые нужны только для пользовательского аккаунта - можно создать здесь
                break;
            }
 
            // при необходимости - создаем другие общие формы здесь
            Application->Run();
        }
        else // авторизация не пройдена
        {
            Application->MessageBox(
                _T("Вы не можете пользоваться приложением, так как не прошли авторизацию"),
                _T("Защита приложения")
            );
        }
Таким образом можно не только отслеживать успешность/неуспешность авторизации, но и создавать свои формы для любого количества групп пользователей.

Единственное, на что хочется обратить внимание - это то, что проделывать все описанные выше операции желательно уже тогда, когда все формы по отдельности уже были созданы и отлажены, самым последним этапом. Изменение настроек проекта (в частности добавление новой формы, или изменение автосоздания формы) приведет к тому, что опять придется изменять основной файл.

В качестве примера реализаций привожу два проекта: первый - иллюстрирует чтение логина/пароля из INI, а второй - создание разных форм для каждой из групп пользователей (проекты были созданы и протестированы в Builder XE2, для создания INI-файла использовался код:
C++
1
2
3
4
5
6
7
8
9
#include <memory>
#include <IdHashMessageDigest.hpp>
 
// ...
 
    std::auto_ptr<TIniFile> ini (new TIniFile(ChangeFileExt(ParamStr(0), ".ini")));
    std::auto_ptr<TIdHashMessageDigest5> hash(new TIdHashMessageDigest5);
    ini->WriteString("users", "volvo", hash->HashStringAsHex("test", TIdTextEncoding::Default));
    ini->WriteString("users", "nata", hash->HashStringAsHex("second", TIdTextEncoding::Default));
)

Проект №1 auth_faq_simple.7z

Проект №2 auth_faq_groups.7z

P.S. Замечания/пожелания/вопросы по этой теме отсылайте мне в ЛС, я постараюсь добавить еще интересные методы авторизации.
25
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.12.2015, 15:33
Ответы с готовыми решениями:

Создание заставки на Форме1 и появление Формы 2 после закрытия Формы1
Здравствуйте. Создал заставку на форме1. Это форма главная. Через промежуток времени она исчезает по таймеру. Должна появляться Форма2, но...

Плавный переход из splash screen в окно авторизации
В общем спустя год взялся за мозги и поймал хорошую штангу, хочу чтобы сначала у программы был сплешскрин потом выскакивало окно...

создание формы авторизации
Здравствуйте помогите пожалуйста доделать скрипт из того что у меня есть файл add_new.php &lt;?php // Подключение к базе...

1
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33187 / 21484 / 8232
Регистрация: 22.10.2011
Сообщений: 36,859
Записей в блоге: 12
16.12.2015, 01:20  [ТС]
Создание заставок (splash-форм) для приложения.


Очень часто сразу после запуска приложения мы видим на экране форму-заставку, так называемую Splash-форму, которая во-первых показывает информацию о программе, а во-вторых - делает ожидание загрузки тяжелой формы более приятным, чем просто сидеть и смотреть, уставившись в пустой экран.


Как же создаются подобные заставки? Все очень просто, и чем-то похоже на создание формы авторизации (наверное, тем, что опять нужно лезть в файл проекта, и менять так порядок создания форм). Итак:

  1. Когда все остальные формы приложения уже созданы и работают, создаем новую форму, которая будет заставкой.
  2. Сразу же идем в свойства приложения, и убираем новую форму из списка автоматически создаваемых (Project->Options->Forms переносим форму из списка Auto-Create в список Available)
  3. Поскольку мы хотим, чтобы форма какое-то время показывалась на экране, то кладем на нее таймер, задаем максимальное время показа заставки, и по таймеру проверяем, не вышло ли еще это время:

    C++
    1
    2
    3
    4
    5
    6
    7
    8
    
    void __fastcall TSplashForm::Timer1Timer(TObject *Sender)
    {
        static int SplashTime = 3000;
        if((::GetTickCount() - FStart > SplashTime) && CanCloseSplash)
        {
            this->Close();
        }
    }
    (о назначении CanCloseSplash я расскажу чуть позже)
  4. Естественно, если не записать в FStart значение GetTickCount() при создании заставки, ничего работать не будет. Поэтому пишем обработчик создания формы:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    void __fastcall TSplashForm::FormCreate(TObject *Sender)
    {
        FStart = ::GetTickCount();
        CanCloseSplash = false; // начальная инициализация всех полей
        Timer1->Interval = 100;
        
        // если кого-то раздражает показ заставки на самом верху,
        // следующую строку можно закомментировать
        FormStyle = fsStayOnTop; 
    }
    Ну вот практически и все, что нужно сделать с формой. Осталось только правильно ее показать.
  5. Идем в главный файл проекта (Project -> View source), и добавляем там показ формы-заставки:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
             SplashForm = new TSplashForm(0); // создаем
             SplashForm->Show(); // и показываем заставку
     
             // теперь продолжаем инициализацию и создание главной формы приложения
             Application->Initialize();
             Application->MainFormOnTaskBar = true;
             Application->CreateForm(__classid(TMainForm), &MainForm);
             
             // сразу после того, как главная форма была создана,
             // можно закрывать заставку (если до этого время не вышло
             // и она не закрылась самостоятельно)
     
             if(SplashForm)
             {
                SplashForm->CanCloseSplash = true; // даем разрешение закрыть заставку
             }
             // и запускаем метод Run, что приведет к показу главной формы
             Application->Run();

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

Можно сделать чуть по-другому: сразу после того, как создалась главная форма, закрывать заставку. Как ни странно, для этого понадобится изменить всего лишь 2 символа в обработчике таймера:
C++
1
2
3
4
5
6
7
8
9
10
11
void __fastcall TSplashForm::Timer1Timer(TObject *Sender)
{
    static int SplashTime = 3000;
    // Меняем "И" на "ИЛИ", и теперь либо закончится время
    // показа заставки, либо CanCloseSplash станет true; заставка
    // закроется при выполнении любого из этих условий
    if((::GetTickCount() - FStart > SplashTime) || CanCloseSplash)
    {
        this->Close();
    }
}
Тестовые проекты
BCB6:
bcb6_splash_simple.7z

XE2:
splash_simple.7z


Это все, конечно, прекрасно, но хочется же красивостей. Давайте попробуем создать заставку в виде изображения с прозрачностью.

Изменений в главном файле проекта почти не будет, единственное, что я поменял - это вместо метода Show вызвал самописный метод ShowSplash:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
         SplashForm = new TSplashForm(0);
         SplashForm->ShowSplash("logo.png"); // <---
 
         Application->Initialize();
         Application->MainFormOnTaskBar = true;
         Application->CreateForm(__classid(TMainForm), &MainForm);
 
         if(SplashForm)
         {
            SplashForm->CanCloseSplash = true;
         }
 
         Application->Run();
А вот реализация класса формы-заставки поменялась значительно. Во-первых, в класс формы добавился прототип того самого метода ShowSplash():
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TSplashForm : public TForm
{
__published:    // IDE-managed Components
    TTimer *Timer1;
    void __fastcall Timer1Timer(TObject *Sender);
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    void __fastcall FormDestroy(TObject *Sender);
private:    // User declarations
    int FStart;
    bool FCanCloseSplash;
 
public:     // User declarations
    __fastcall TSplashForm(TComponent* Owner);
    void __fastcall ShowSplash(String fn); // <---
 
    __property bool CanCloseSplash = {read = FCanCloseSplash, write = FCanCloseSplash};
};
Ну, и реализация (в XE+ использовался модуль Vcl.Imaging.pngimage.hpp)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
void __fastcall Create_Premult_Bitmap(Graphics::TBitmap *bm)
{
    for (int y = 0; y < bm->Height; y++)
    {
        Vcl::Imaging::Pngimage::TByteArray *dst =
            (Vcl::Imaging::Pngimage::TByteArray*)bm->ScanLine[y];
        for (int x = 0; x < bm->Width; x++)
        {
            dst->data[x * 4] = dst->data[x * 4] * dst->data[x * 4 + 3] >> 8;
            dst->data[x * 4 + 1] =
                dst->data[x * 4 + 1] * dst->data[x * 4 + 3] >> 8;
            dst->data[x * 4 + 2] =
                dst->data[x * 4 + 2] * dst->data[x * 4 + 3] >> 8;
        };
    };
}
 
void __fastcall Load_Logo(Graphics::TBitmap *bm, String FileName)
{
    std::auto_ptr<TPngImage> png (new TPngImage);
    png->LoadFromFile(FileName);
    bm->PixelFormat = pf32bit;
    bm->Width = png->Width;
    bm->Height = png->Height;
    for (int y = 0; y < png->Height; y++)
    {
        Vcl::Imaging::Pngimage::TByteArray *alpha = png->AlphaScanline[y];
        TRGBLine *src = (TRGBLine*)png->Scanline[y];
        Vcl::Imaging::Pngimage::TByteArray *dst =
            (Vcl::Imaging::Pngimage::TByteArray*)bm->ScanLine[y];
        for (int x = 0; x < png->Width; x++)
        {
            dst->data[x * 4] = src->data[x].rgbtBlue;
            dst->data[x * 4 + 1] = src->data[x].rgbtGreen;
            dst->data[x * 4 + 2] = src->data[x].rgbtRed;
            dst->data[x * 4 + 3] = alpha->data[x];
        }
    }
}
 
void __fastcall TSplashForm::ShowSplash(String fn)
{
    BorderStyle = bsNone;
    Position = poDesktopCenter;
    this->FormStyle = fsStayOnTop;
 
    SIZE s1;
 
    BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
 
    TPoint p = Classes::Point(0, 0);
    ::SetWindowLong(Handle, GWL_EXSTYLE, ::GetWindowLong(Handle,
        GWL_EXSTYLE) | WS_EX_LAYERED);
 
    std::auto_ptr<Graphics::TBitmap> image (new Graphics::TBitmap);
    Load_Logo(image.get(), ExpandFileName(ExtractFilePath(ParamStr(0))) + fn);
    Create_Premult_Bitmap(image.get());
    s1.cx = image->Width;
    s1.cy = image->Height;
 
    Width = image->Width;
    Height = image->Height;
 
    std::auto_ptr<Graphics::TBitmap> layer (new Graphics::TBitmap);
    layer->PixelFormat = pf32bit;
    layer->Width = s1.cx;
    layer->Height = s1.cy;
    layer->Canvas->Brush->Color = RGB(0, 0, 0);
    layer->Canvas->FillRect(layer->Canvas->ClipRect);
 
    ::AlphaBlend(layer->Canvas->Handle, 0, 0, image->Width, image->Height,
        image->Canvas->Handle, 0, 0, image->Width, image->Height, blend);
    Create_Premult_Bitmap(layer.get());
    ::UpdateLayeredWindow(this->Handle, 0, NULL, &s1, layer->Canvas->Handle, &p,
        0, &blend, ULW_ALPHA);
 
    Show();
}
Тестовые проекты
BCB6:
собрать не получилось. Я уже говорил, что использую Portable версию Билдера, туда нельзя добавлять новые компоненты, нельзя даже просто откомпилировать pas-файл, поэтому работать с PNG не представляется возможным

XE2:
splash_non_rect.7z



А теперь о грустном. У первого метода есть недостаток (на самом деле он есть и у второго, но поскольку картинка обычно статичная - он не так бросается в глаза). Заключается он в следующем: если при инициализации основной формы (как раз в то время, когда показывается заставка) не вызывать периодически Application->ProcessMessages(), как я делал в тестовом приложении, то форма не будет обновляться. Она просто повиснет в том состоянии, в котором была создана, и на нее не положишь ни ProgressBar, ни Label, в которые можно вывести какую-то информацию о том, на каком этапе находится сейчас процесс загрузки приложения.

Чтобы этого избежать можно:
  1. Вынести все действия по инициализации в отдельный поток.
  2. Создать и показать заставку
  3. Запустить поток инициализации
  4. По завершению работы потока закрывать заставку

Убиваем двух зайцев: во-первых, ОС не считает заставку "зависшей" формой, во-вторых, пользователь тоже так не считает, поскольку видит, что информация на ней меняется. Приведу, кому интересно, пример приложения, реализующего вышеописанную схему, с потоком. Запустите и посмотрите (для того, чтобы проверить - добавил искусственных задержек в поток)

Тестовые проекты
BCB6:
bcb6_splash_adv.7z

XE2:
splash_adv.7z



Ну вот и все, пожалуй, о Splash-формах.


P.S. Замечания/пожелания/вопросы приветствуются, обращайтесь в ЛС, если будет что-то интересное - добавлю в пост.
23
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.12.2015, 01:20
Помогаю со студенческими работами здесь

Создание формы авторизации
1) Подключаем таблицу к форме но не отображаем 2) Есть два поля для ввода (DBEdit или Edit??) 3) Как сделать чтобы сравнивало значения...

Создание формы авторизации на С++ в Qt
Всем привет!!! Народ вот такая проблема сам я изучал и писал в основном на C#, но моё начальство на работе захотело приложение по линукс...

Создание формы авторизации на С++ в Qt
Всем привет! Народ вот такая проблема сам я изучал и писал в основном на C#, но моё начальство на работе захотело приложение по линукс и...

Создание формы авторизации
Добры день друзья я только начинаю программировать на язык (C# windows form 2010 ) хочу создать форму авторизация с помощь textbox и...

Создание формы входа и авторизации
нужно написать простенькую программу где будет окно входа и авторизации


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Закрытая тема Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru