Kolejność WM_NCPAINT i WM_SIZE

Kolejność WM_NCPAINT i WM_SIZE
CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0

Zauważyłem dosyć dziwną rzecz. W przypadku "niemanualnej" zmiany rozmiaru formy (np. poprzez Form1.Width: = 600) komunikat WM_NCPAINT odpowiedzialny za malowanie formy w części poza klientem (czyli np. ramki i przyciski systemowe) wysyłany jest jako pierwszy, a WM_SIZE odpowiedzialny za faktyczną zmianę rozmiaru formy i kontrolek, wysyłany jest później.

Moje pytanie - jaki sens ma namalowanie ramki dla okna o rozmiarze np. 350 x 200, skoro za chwilę okno zmieni rozmiar do powiedźmy 730 x 490 i ramka będzie niewiele warta, bo namalowana dla nieaktualnego już rozmiaru? Ja poradziłem sobie w ten sposób, że po WM_SIZE wysyłam jeszcze raz WM_NCPAINT i zmuszam program do ponownego narysowania ramki (co swoją drogą jest nieco nieekonomiczne, bo muszę rysowanie wykonać dwukrotnie). Działać działa, ale jakoś nie daje mi to spokoju. Ktoś wie, czemu Windows stosuje taką kolejność? Czyżby zmiana rozmiaru okna nie "szkodziła" jego domyślnym ramkom?

edytowany 1x, ostatnio: Crow
szopenfx
  • Rejestracja:prawie 21 lat
  • Ostatnio:5 miesięcy
0

Kto wie - może przed zmianą rozmiaru np. trzeba wyłączyć przycisk od maksymalizacji i to pokazać:>? A może to po prostu niedopatrzenie... Czy naprawdę jest to takie ważne gdy aplikacja przyjmuje setki innych komunikatów w tym samym czasie? No i kto spierniczył MS czy Emba to już zagadka.

CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0

Już wiem. Po prostu to dziadostwo działa tak, że rysuje nową ramkę jeszcze przed zmianą rozmiaru całego klienta, przesyłając do WM_NCPAINT odpowiednie wymiary w wParam, zakodowane jako region (HRGN). Staram się odczytywać te liczby konwertując HRGN na TRect (przy pomocy GetRgnBox), ale czasem wychodzą mi jakieś krzaki (bo inny region zostaje wysłany przy konstruktorze formy, a inny przy np. zmianie rozmiaru okna). Czytałem na MSDN, że taki odebrany w komunikacie region, trzeba jeszcze rzutować na okno (clipping). Jak uda mi się coś sklecić, to nie omieszkam napisać :).

edytowany 3x, ostatnio: Crow
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Tuchów
  • Postów:12169
0

@Crow: ale nad czym Ty się zastanawiasz?

System działa tak a nie inaczej, VCL też jest zaimplementowany tak a nie inaczej, więc nie masz na to zbytnio wpływu; Redundancja to nieodzowna cecha wszelkich bibliotek komponentów - trzeba się z tym pogodzić, albo napisać swoją :]


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:minuta
  • Lokalizacja:Gorlice
0

Po mojemu to zwykły przypadek komunikat WM_NCPAINT został wywołany z zupełnie innego powodu, być może podczas testów zakrywałeś okno (przynajmniej częściowo) dlatego system wysłał komunikat nakazujący jego odmalowanie.Ogólnie nie jest zalecane aby user wnikał w komunikaty dotyczące tego obszaru okna choć wiadomo że czasem trzeba (np. gdy trzeba rysować własne przyciski na belce tytułowej) ale ogólnie nie ma co wnikać i lepiej pozostawić to systemowi i naprawdę nie ma co drążyć.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 15 godzin
0

Moje pytanie - jaki sens ma namalowanie ramki dla okna o rozmiarze np. 350 x 200, skoro za chwilę okno zmieni rozmiar do powiedźmy 730 x 490 i ramka będzie niewiele warta, bo namalowana dla nieaktualnego już rozmiaru? Ja poradziłem sobie w ten sposób, że po WM_SIZE wysyłam jeszcze raz WM_NCPAINT i zmuszam program do ponownego narysowania ramki

Nie wiem jaki sens, ale skoro od xx lat tak jest i działa to znaczy że jest dobrze. Wysyłając ręcznie WM_NCPAINT ryzykujesz dziwnymi skutkami ubocznymi - jeśli nie dzisiaj to w przyszłości, albo przy innej konfiguracji (włączone/wyłączone Aero, zdalny pulpit itp.)

CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0

W tym rzecz, że niby działa, ale nie do końca optymalnie ;).

Apka rysuje ramki, następnie skaluje i przerysowuje klienta, a potem - tym razem już z mojej inicjatywy - jeszcze raz rysuje ramki. Trochę mi się to nie podoba, bo jednak wymusza dodatkowe, zupełnie niepotrzebne rysowanie. Samo rysowanie oczywiście wywołuję inaczej, niż poprzez wysłanie WM_NCPAINT. Czytałem na MSDN, żeby nigdy nie rozsyłać ani WM_NCPAINT ani WM_PAINT, bo to tylko sprawia problemy. Zamiast tego - za radą MSDN - stosuję RedrawWindow.

I wiem już na pewno, że WM_NCPAINT jest wysyłany nieprzypadkowo w takiej kolejności. Nie wiem czemu, ale Windows uznaje narysowanie ramek za priorytet i stawia go wyżej, niż np. zmianę rozmiaru klienta czy przerysowanie kontrolek w nim umiejscowionych. Staram się to prawidłowo obsłużyć, odczytując region wysłany w wParam, ale póki co idzie tak sobie. Pierwsze WM_NCPAINT, odebrane z automatu zaraz po WM_NCCALCSIZE liczącym rozmiary okna, zawiera jakieś bzdety (ramka w ogóle mi się nie rysuje), a późniejsze (np. po zmianie rozmiaru formy czy maksymalizacji), też bywają koślawe. Czytałem na MSDN, że ten region trzeba jeszcze rzutować jakoś na okno, ale jeszcze nie rozgryzłem odpowiednich funkcji ;d.

PS. Wszyscy tak straszyli tym WinAPI, a mi się tu bardziej podoba niż w VCL. Niby też niewiele rozumiem, ale przynajmniej fajna dokumentacja jest ;].

EDIT

Udało mi się prawidłowo obsłużyć region wysłany do WM_NCPAINT w wParam. Niestety, on też przesyła nieaktualne już wymiary okna, czyli jeszcze PRZED przeliczeniem na nowy rozmiar. Nie rozumiem tego. Skoro jednym z pierwszych komunikatów wywoływanych po manipulacji wartościami width i height jest WM_NCCALCSIZE (przeliczający wymiary całego okna), to na jaki ciul wysyłać do WM_NCPAINT szablon ze starymi danymi? Podejrzewam, że Windows ma jakieś dziwne sposoby rysowania swoich ramek (w nowszych wersjach Win'a, nawet nie za bardzo da się na nich coś nabazgrać, nawet po prawidłowym założeniu uchwytu na WindowDC).

Jakieś pomysły, jak z tego wybrnąć?

Ja myślę o wprowadzeniu globalnej zmiennej, która będę się aktualizować wraz z obsługą WM_NCCALCSIZE. Zmienna będzie trzymać wymiary okna, żeby WM_NCPAINT mógł z nich skorzystać, zamiast bazować na nieaktualnym parametrze otrzymywanym w wParam. To chyba bardziej wydajne niż ponowne inicjowanie WM_NCPAINT, zwłaszcza, że RedrawWindow aktywuje jeszcze masę innych operacji (w tym repaint całego klienta i wszystkich kontrolek), więc to strasznie niegospodarne.

EDIT 2

Działa!

edytowany 5x, ostatnio: Crow
CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0

Problem w ogóle niezwiązany z tematem, ale nie chcę zaśmiecać forum nowym.

Czy da się - bez tworzenia nowego komponentu - nadpisać wartość (property) komponentu? Mój moduł pracuje tylko z BorderStyle = bsNone i takie właśnie property chce narzucać każdej formie, modyfikując klasę TForm. Problem w tym, że zmiana tej właściwości nie może nastąpić w konstruktorze formy, bo to zbyt późno. Inne zdarzenia już wcześniej - bazując na tym ustawieniu - dokonują pewnych przekształceń i obliczeń w obrębie okna.

woolfik
  • Rejestracja:ponad 17 lat
  • Ostatnio:około 7 godzin
  • Postów:1596
1

Tak możesz użyć do tego metod RTTI wystarczy dodać do uses RTTI lub ustawić helpera dla klasy TForm. Jest jeszcze jedna metoda ale jest to dość zawiane i myślę, że nie ma sensu o tym pisać ;)

edytowany 2x, ostatnio: woolfik
CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0

To ja jednak poproszę o tę drugą metodę, bo mój kompilator nie obsługuje RTTI ani ClassHelperów ;d.

edytowany 1x, ostatnio: Crow
0
Crow napisał(a):

Zauważyłem dosyć dziwną rzecz. W przypadku "niemanualnej" zmiany rozmiaru formy (np. poprzez Form1.Width: = 600) komunikat WM_NCPAINT odpowiedzialny za malowanie formy w części poza klientem (czyli np. ramki i przyciski systemowe) wysyłany jest jako pierwszy, a WM_SIZE odpowiedzialny za faktyczną zmianę rozmiaru formy i kontrolek, wysyłany jest później.

Moje pytanie - jaki sens ma namalowanie ramki dla okna o rozmiarze np. 350 x 200, skoro za chwilę okno zmieni rozmiar do powiedźmy 730 x 490 i ramka będzie niewiele warta, bo namalowana dla nieaktualnego już rozmiaru? Ja poradziłem sobie w ten sposób, że po WM_SIZE wysyłam jeszcze raz WM_NCPAINT i zmuszam program do ponownego narysowania ramki (co swoją drogą jest nieco nieekonomiczne, bo muszę rysowanie wykonać dwukrotnie). Działać działa, ale jakoś nie daje mi to spokoju. Ktoś wie, czemu Windows stosuje taką kolejność? Czyżby zmiana rozmiaru okna nie "szkodziła" jego domyślnym ramkom?

Pewnie sam to psujesz i takie głupoty otrzymujesz.

NCPaint jaki i inne NC* należy obsługiwać prawidłowo, a wtedy nie ma problemów.

CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0
fol napisał(a):
Crow napisał(a):

Zauważyłem dosyć dziwną rzecz. W przypadku "niemanualnej" zmiany rozmiaru formy (np. poprzez Form1.Width: = 600) komunikat WM_NCPAINT odpowiedzialny za malowanie formy w części poza klientem (czyli np. ramki i przyciski systemowe) wysyłany jest jako pierwszy, a WM_SIZE odpowiedzialny za faktyczną zmianę rozmiaru formy i kontrolek, wysyłany jest później.

Moje pytanie - jaki sens ma namalowanie ramki dla okna o rozmiarze np. 350 x 200, skoro za chwilę okno zmieni rozmiar do powiedźmy 730 x 490 i ramka będzie niewiele warta, bo namalowana dla nieaktualnego już rozmiaru? Ja poradziłem sobie w ten sposób, że po WM_SIZE wysyłam jeszcze raz WM_NCPAINT i zmuszam program do ponownego narysowania ramki (co swoją drogą jest nieco nieekonomiczne, bo muszę rysowanie wykonać dwukrotnie). Działać działa, ale jakoś nie daje mi to spokoju. Ktoś wie, czemu Windows stosuje taką kolejność? Czyżby zmiana rozmiaru okna nie "szkodziła" jego domyślnym ramkom?

Pewnie sam to psujesz i takie głupoty otrzymujesz.

NCPaint jaki i inne NC* należy obsługiwać prawidłowo, a wtedy nie ma problemów.

Eeee nie? Dla testu zrobiłem coś takiego, że w obsłudze komunikatu miałem tylko:

Kopiuj
procedure OBSŁUGA_KOMUNIKATU
begin
Log.Lines.Add('NAZWA KOMUNIKATU');
inherited;
end;

Po sprawdzeniu loga, widać jak na dłoni, jaka jest kolejność. WM_NCPAINT jest wysyłany przed WM_SIZE, bo Windows najpierw rysuje ramki i elementy interface'u a potem resztę. Nie wierzysz, to sprawdź u siebie :).

0

Może nawet tak być, w co i tak wątpię, ponieważ API było robione i doskonalone przez 20 lat z górką, więc tam aż takich bagów raczej nie powinno być!

Ale gdy faktycznie jest tak jak mówisz, to i tak nie powinno to wpływać na działanie aplikacji!

Bowiem, w systemach typu GUI, Ty zawsze masz obowiązek przerysować swoje okno - na żądanie systemu!

Mało: masz to robić w dowolnej żądanej rozdzielczości, bo user może zmienić rozdzielczość ekranu w dowolnej chwili,
albo chce to wydrukować - przesłać na drukarkę, która ma zwykle z 10 razy większą rozdzielczość od monitora!

Użyj niezależnego narzędzia do śledzenia komunikatów, np. winsight.

edytowany 1x, ostatnio: flowCRANE
CR
  • Rejestracja:ponad 16 lat
  • Ostatnio:11 miesięcy
0
fol napisał(a):

Może nawet tak być, w co i tak wątpię, ponieważ API było robione i doskonalone przez 20 lat z górką, więc tam aż takich bagów raczej nie powinno być!

Ale gdy faktycznie jest tak jak mówisz, to i tak nie powinno to wpływać na działanie aplikacji!

Bowiem, w systemach typu GUI, Ty zawsze masz obowiązek przerysować swoje okno - na żądanie systemu!

Mało: masz to robić w dowolnej żądanej rozdzielczości, bo user może zmienić rozdzielczość ekranu w dowolnej chwili,
albo chce to wydrukować - przesłać na drukarkę, która ma zwykle z 10 razy większą rozdzielczość od monitora!

Ale czemu nazywasz to "bagiem"? Może tak właśnie miało być?

Jak nie wierzysz, napisz sobie na szybko obsługę WM_NCPAINT i odczytaj wParm, w którym zakodowany jest region (HRGN). Wtedy zobaczysz, że przesyłany jest tam rozmiar okna jeszcze przed zmianą formy, a nie już zaktualizowany. Testowałem to na czystej apce, bez obsługi jakichkolwiek komunikatów poza właśnie WM_NCPAINT, także wykluczam moją winę.

A tak w ogóle, to z tym już sobie poradziłem. Wrzuciłem do klasy zmienną, która po prostu zapisuje wymiary okna zaraz po WM_NCCALCSIZE (następującym na długo przed WM_SIZE) i potem WM_NCPAINT - gdy przyjdzie jego kolej - sobie z tego korzysta, zamiast z kulawego wParm.

Problem mam taki, że chcę odgórnie wymusić na formie BorderStyle = bsNone, jeszcze zanim apka zacznie wykonywać jakiekolwiek kalkulacje związane z formą. Próbowałem to zrobić w konstruktorze, w ReadState, w CreateParms, ale to ciągle zbyt późno. Po prostu źle mi przelicza rozmiar klienta, bo już wcześniej dokonuje przeliczeń w oparciu o BorderStyle pobrane z inspektora. I tak np. w inspektorze ClientWidth wynosi 1200, a po skompilowaniu zmienia się w 1186. Nie byłoby problemem wyrównać to ręcznie, gdyby nie fakt, że rozmiar klienta zmienia się w zależności o wartości BorderStyle w inspektorze. Inny pojawia się dla bsNone, inny dla bsSingle, inny dla bsSizeable... I to pomimo faktu, że w konstruktorze narzucam mu bsNone, który po odpaleniu aplikacji faktycznie zostaje wykonany (próbowałem na różne sposoby, także przez SetWindowLong i zmianę WindowStyle). tylko co z tego, skoro rozmiar klienta jest już wtedy skopany.

Wydaje mi się więc, że albo muszę odnaleźć pierwotny komunikat, który za to odpowiada, albo po prostu zmienić property BorderStyle jeszcze zanim apka cokolwiek przeliczy. Z tym ClassHelperem to była niezła sugestia, tylko mój kompilator (Delphi 7), tego nie ma :).

Ja tak to sprawdzam:

Kopiuj
procedure TForm1.NonClientPaint(var MSG: TWMNCPAINT);
var
  Rec: TRect;
begin
  inherited;
  GetRgnBox(MSG.RGN, Rec);

  ShowMessage('Width ' + IntToStr(Rec.Right - Rec.Left));
  ShowMessage('Height ' + IntToStr(Rec.Bottom - Rec.Top));
end;

Potem w Buttonie ustawiam sobie coś takiego:

Kopiuj
 Width:= 700

Okienko i tak wypluwa mi pierwotne Width = 1200.

edytowany 5x, ostatnio: Crow
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 15 godzin
0

Nie wiem czemu, ale Windows uznaje narysowanie ramek za priorytet i stawia go wyżej, niż np. zmianę rozmiaru klienta czy przerysowanie kontrolek w nim umiejscowionych.

To jest akurat zrozumiałe. Ramka okna (zwłaszcza domyślna, windowsowa) jest przez użytkownika postrzegana bardziej jako element systemu niż element programu. Jeśli błędne działanie programu miałoby oznaczać psucie się ramki, ludzie by krzyczeli „jaki głupi ten Windows, jak program zmuli to nawet ramki okna nie potrafi prawidłowo narysować”. Dlatego ramka psuje się jako ostatnia ;-) /no, chyba że akurat przy ramce coś celowo grzebiesz/

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)