Создайте форму без полей без потери команд Windows

Я изменил свою форму на форму без полей, я просто изменил свойство BorderStyle на bsNone, но теперь мое приложение теряет привязку Windows и некоторые команды, такие как

WIN + ↑ (Align the form Client)
WIN + ↓ (Minimize the form)
WIN + →(Align the form Right)
WIN + ←(Align the form Left)

Я пытался установить BorderStyle: bsSizeable и использовать приведенный ниже код внутри FormCreate, но это не сработало:

procedure TfrmBase.FormCreate(Sender: TObject);
begin
  SetWindowLong(Handle
               ,GWL_STYLE
               ,GetWindowLong(Handle, GWL_STYLE)
                AND (NOT WS_CAPTION)
                AND (NOT WS_THICKFRAME)
               );


  Refresh;
  FormColor := oLauncher.oCor;
end;

Это приводит к:

Создайте форму без полей без потери команд Windows

Изображение выше - это то, что я хочу, но команды Windows, о которых я уже упоминал, не работают.

Есть ли способ установить BorderStyle: bsNone и не потерять эти команды?

ОТРЕДАКТИРОВАНО

Если я использую WS_THICKFRAME, моя форма возвращает небольшую верхнюю границу, и команды Windows работают хорошо, но мне не нужна эта верхняя граница.

Создайте форму без полей без потери команд Windows

ОТРЕДАКТИРОВАНО 2

Я был очень близок к ожидаемому результату, но пока есть небольшая проблема...

Я положил это на свой FormCreate

SetWindowLong(Handle
             ,GWL_STYLE
             ,GetWindowLong(Handle, GWL_STYLE)
              AND (NOT WS_CAPTION)
              );

И я создаю метод

private
   procedure WmNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;

а потом

procedure TfrmBase.WmNCCalcSize(var Msg: TWMNCCalcSize);
begin
  inherited;
  if Msg.CalcValidRects then
  begin
    InflateRect(Msg.CalcSize_Params.rgrc[0], 0, 6);
    Msg.Result := 0;
  end;
end;

I got this method here

Теперь граница исчезла, но когда моя форма теряет фокус, снова отображается верхняя/нижняя граница....

Как я могу этого избежать?

Создайте форму без полей без потери команд Windows


РЕШЕНО

Границу я оставил как BorderStyle: bsSizeable, потом сделал так:

private
  procedure WmNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;
[...]
procedure TfrmBase.WmNCCalcSize(var Msg: TWMNCCalcSize);
var
  R: TRect;
begin
  if not Msg.CalcValidRects then
    R := PRect(Msg.CalcSize_Params)^;
  inherited;
  if Msg.CalcValidRects then
    Msg.CalcSize_Params.rgrc0 := Msg.CalcSize_Params.rgrc1
  else
    PRect(Msg.CalcSize_Params)^ := R;

  Msg.Result := 0;
end;

procedure TfrmBase.FormCreate(Sender: TObject);
begin
  BorderStyle := bsNone;
  SetWindowLong(Handle
               ,GWL_STYLE
               ,WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW
               );
end;

procedure TfrmBase.FormShow(Sender: TObject);
begin
  Width := (Width - 1);
end;

Solution at GitHUB

I've create a repository here

так что в основном вы хотите это?

whosrdaddy 12.02.2019 18:29

@whosrdaddy Да, я уже сделал это на C# с WPF, но я не знаю, как применить эту логику в Delphi... Я сделал это на C# и не потерял команды Windows.

Matheus Miranda 12.02.2019 18:35

в основном вы делаете то же самое (переопределяете параметры createparams и переопределяете wndproc)...

whosrdaddy 12.02.2019 18:36

Чтобы системная команда работала, у вас должна быть включена соответствующая системная команда. Я имею в виду, что вам нужен WS_SIZEBOX, например, для win->, чтобы включить SC_SIZE. Но это связано с толстой рамой. IOW, рама - это то, что заставляет это работать.

Sertac Akyuz 12.02.2019 18:55

@SertacAkyuz Я пробовал это, но появляется небольшая граница, посмотрите мой вопрос еще раз, пожалуйста.

Matheus Miranda 12.02.2019 19:04

Это было моей точкой зрения.

Sertac Akyuz 12.02.2019 19:07

Привет, @SertacAkyuz, я нашел твой ответ здесь, который мне немного помог. Знаете ли вы, как мне избежать проблемы с ОТРЕДАКТИРОВАНО 2?

Matheus Miranda 13.02.2019 14:38

Возможно, вы на правильном пути. Возможно, вам следует нарисовать границу самостоятельно.

Sertac Akyuz 13.02.2019 14:47

Я не понимаю сделки, хотя. В конце концов, у вас есть большое окно, почему вы не хотите, чтобы оно было правильным?

Sertac Akyuz 13.02.2019 14:48

Я хочу создать свою собственную строку заголовка без потери команд Windows и без использования стилей... Но если я использую BorderStyle: bsNone, моя форма теряет эти команды, тогда я использую BorderStyle: bsSizeable, и я работаю, чтобы скрыть заголовок и его верхняя граница.

Matheus Miranda 13.02.2019 14:57

RE (решено): «* оставил границу как BorderStyle: bsSizeable*» — обратите внимание на «BorderStyle := bsNone;» в обработчике события OnCreate, если вы его не укажете, это не сработает, настройка дизайна не вступит в силу. Во всяком случае, я предполагаю, что «Ширина - 1» вызывает обновление кадра, вы, вероятно, можете добиться этого с помощью SetWindowPos (SWP_FRAMECHANGED) или RedrawWindow (RDW_FRAME).

Sertac Akyuz 13.02.2019 19:40

@SertacAkyuz Если я уйду BorderStyle: = bsNone;, когда я использую WIN + Arrows, окно выглядит странно, некоторые части экрана становятся черными

Matheus Miranda 14.02.2019 11:24

Хорошо спасибо. Кажется, в разных средах отображается разное поведение, мне это не нравится. Попробуйте протестировать как можно больше ОС перед развертыванием.

Sertac Akyuz 14.02.2019 15:25

Это внутреннее программное обеспечение, которое помогает моей команде изо дня в день, до сих пор я тестировал на Windows 10 и Windows 7, и с этим изменением, которое я сделал, оно хорошо работает на них обоих.

Matheus Miranda 14.02.2019 16:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
14
411
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Некоторые из команд, на которые вы ссылаетесь, являются системными командами, связанными с изменением размера окна. Для этого нужна толстая рамка, без нее "WIN+право" и "WIN+лево" работать не будут. Кроме того, для работы команд WIN + вверх/вниз вам понадобится окно свертывания и окно максимизации.

Лучше всего начать с нуля и включить нужные стили, иначе VCL может помешать. Если есть возможность воссоздать вашу форму, поместите стиль в переопределение CreateWnd.

procedure TForm1.FormCreate(Sender: TObject);
begin
  BorderStyle := bsNone;
  SetWindowLong(Handle, GWL_STYLE, WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW);
end;


Тогда есть кадр, который вам не нужен. В редактировании вопроса вы раздуваете прямоугольник клиента, чтобы избавиться от него. Не угадывайте ширину/высоту кадра, сделайте это, как показано ниже.

procedure TForm1.WMNCCalcSize(var Message: TWMNCCalcSize);
var
  R: TRect;
begin
  if not Message.CalcValidRects then
    R := PRect(Message.CalcSize_Params)^;
  inherited;
  if Message.CalcValidRects then
    Message.CalcSize_Params.rgrc0 := Message.CalcSize_Params.rgrc1
  else
    PRect(Message.CalcSize_Params)^ := R;
  Message.Result := 0;
end;

На этом этапе чтение документация для сообщения является обязательным, параметры имеют разные значения на разных этапах и т. д.


Вышеприведенное оставляет окно без какой-либо неклиентской области. Прямоугольник клиента равен прямоугольнику окна. Хотя заголовок не виден, вы можете активировать системное меню, нажав Alt+Пробел. Проблема в том, что система настаивает на отображении состояния активации. Теперь он рисует рамку в клиентской области!!

Избавьтесь от него, перехватив WM_NCACTIVATE, он же нужен для отрисовки вашего заголовка по статусу активации:

procedure TForm1.WMNCActivate(var Message: TWMNCActivate);
begin
  if Message.Active then
    // draw active caption
  else
    // draw incactive caption

  // don't call inherited
end;


Возможно, вам придется иметь дело с некоторыми глюками, испорченное окно имеет последствия. Например, в моем тесте свернутая форма не имеет связанного значка в диалоговом окне alt + tab.



Ниже мой тестовый образец полностью.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure WMNCActivate(var Message: TWMNCActivate); message WM_NCACTIVATE;
    procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  BorderStyle := bsNone;
  SetWindowLong(Handle, GWL_STYLE, WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW);
end;

procedure TForm1.WMNCActivate(var Message: TWMNCActivate);
begin
  if Message.Active then
    // draw active caption
  else
    // draw incactive caption

  // don't call inherited
end;

procedure TForm1.WMNCCalcSize(var Message: TWMNCCalcSize);
var
  R: TRect;
begin
  if not Message.CalcValidRects then
    R := PRect(Message.CalcSize_Params)^;
  inherited;
  if Message.CalcValidRects then
    Message.CalcSize_Params.rgrc0 := Message.CalcSize_Params.rgrc1
  else
    PRect(Message.CalcSize_Params)^ := R;
  Message.Result := 0;
end;

end.

Это сработало -, ты мне очень помог!! Теперь мне просто нужно внести некоторые коррективы...

Matheus Miranda 13.02.2019 18:32

Другие вопросы по теме