// Draw a divider using XOR mode
UpdateCanvas canvas(_hwndParent);
ModeSetter mode(canvas, R2_NOTXORPEN);
canvas.Line (_dragX, 0, _dragX, _cy - 1);
}
ΠΠΎΠ³Π΄Π° Π»Π΅Π²Π°Ρ ΠΊΠ½ΠΎΠΏΠΊΠ° ΠΌΡΡΠΈ Π½Π°ΠΆΠ°ΡΠ° Π½Π°Π΄ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΎΠΉ ΠΎΠ±Π»Π°ΡΡΡΡ ΡΠ°ΡΡΠ΅ΠΏΠΈΡΠ΅Π»Ρ, ΠΌΡ Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ Π·Π°Π΄Π°ΡΠΈ. Π‘Π½Π°ΡΠ°Π»Π° ΠΌΡ ΡΠΈΠΊΡΠΈΡΡΠ΅ΠΌ ΠΌΡΡΡ. ΠΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΌΠΎΠΆΠ΅Ρ ΠΈ, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π±ΡΠ΄Π΅Ρ, ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ°ΡΡ ΠΊΡΡΡΠΎΡ ΠΌΡΡΠΈ Π²Π½Π΅ ΠΏΠΎΠ»ΠΎΡΠΊΠΈ ΡΠ°ΡΡΠ΅ΠΏΠΈΡΠ΅Π»Ρ. Π€ΠΈΠΊΡΠ°ΡΠΈΡ ΠΌΡΡΠΈ Π³Π°ΡΠ°Π½ΡΠΈΡΡΠ΅Ρ, ΡΡΠΎ Π²ΡΠ΅ Π΅Π΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π±ΡΠ΄ΡΡ ΡΠ΅ΠΏΠ΅ΡΡ Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½Ρ ΠΊ Π½Π°ΠΌ, Π΄Π°ΠΆΠ΅ Π² ΡΠΎΠΌ ΡΠ»ΡΡΠ°Π΅, ΠΊΠΎΠ³Π΄Π° ΠΊΡΡΡΠΎΡ ΠΌΡΡΠΈ Π±ΡΠ΄Π΅Ρ Π±Π»ΡΠΆΠ΄Π°ΡΡ ΠΏΠΎ Π²ΡΠ΅ΠΌΡ ΡΠΊΡΠ°Π½Ρ.
ΠΠ°ΡΠ΅ΠΌ ΠΌΡ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ΅ΠΌ Π»ΠΎΠΊΠ°Π»ΡΠ½ΡΠ΅ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ ΡΠΏΠ»ΠΈΡΡΠ΅ΡΠ° Π² ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ ΡΠΎΠ΄ΠΈΡΠ΅Π»ΡΡΠΊΠΎΠ³ΠΎ ΠΎΠΊΠ½Π°. ΠΡ Π΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ ΠΊΠΎΠ½Π²Π΅ΡΡΠ°ΡΠΈΠ΅ΠΉ Π½Π°ΡΠ°Π»ΡΠ½ΡΡ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°Ρ ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ ΠΊ ΡΠΊΡΠ°Π½Π½ΡΠΌ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠ°ΠΌ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠ°ΠΌ Π΄ΠΈΡΠΏΠ»Π΅Ρ ΠΈ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π½Π°ΡΠ°Π»ΡΠ½ΡΠ΅ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ Π½Π°ΡΠ΅Π³ΠΎ ΡΠ°ΡΡΠ΅ΠΏΠΈΡΠ΅Π»Ρ ΡΠ°ΠΊΠΆΠ΅ ΠΊ ΡΠΊΡΠ°Π½Π½ΡΠΌ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠ°ΠΌ Π΄ΠΈΡΠΏΠ»Π΅Ρ. Π Π°Π·Π½ΠΈΡΠ° Π΄Π°Π΅Ρ Π½Π°ΠΌ Π½Π°ΡΠ°Π»ΡΠ½ΠΎΠ΅ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΎΠΉ ΠΎΠ±Π»Π°ΡΡΠΈ ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ. ΠΡ Π΄Π΅Π»Π°Π΅ΠΌ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ Π°ΡΠΈΡΠΌΠ΅ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ, ΡΡΠΎΠ±Ρ Π½Π°ΠΉΡΠΈ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ x ΡΠ΅Π½ΡΡΠ° ΡΠ°ΡΡΠ΅ΠΏΠΈΡΠ΅Π»Ρ, ΠΏΠΎΡΠΎΠΌΡ ΡΡΠΎ ΡΡΠΎ - ΡΠΎ, ΡΡΠΎ ΠΌΡ Π±ΡΠ΄Π΅ΠΌ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ°ΡΡ.
Π§ΡΠΎΠ±Ρ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ, ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ°ΡΡΠ΅ΠΌΡ ΡΠΏΠ»ΠΈΡΡΠ΅Ρ, ΠΎΠ±ΡΠ°ΡΠ½ΡΡ ΡΠ²ΡΠ·Ρ, ΠΌΡ ΡΠΈΡΡΠ΅ΠΌ ΠΎΠ΄ΠΈΠ½ΠΎΡΠ½ΡΡ Π²Π΅ΡΡΠΈΠΊΠ°Π»ΡΠ½ΡΡ Π»ΠΈΠ½ΠΈΡ, ΠΊΠΎΡΠΎΡΡΡ Π±ΡΠ΄Π΅ΠΌ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ°ΡΡ ΠΏΠΎΠΏΠ΅ΡΠ΅ΠΊ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΎΠΉ ΠΎΠ±Π»Π°ΡΡΠΈ ΡΠΎΠ΄ΠΈΡΠ΅Π»ΡΡΠΊΠΎΠ³ΠΎ ΠΎΠΊΠ½Π°. ΠΠ±ΡΠ°ΡΠΈΡΠ΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° Π΄Π²Π΅ Π²Π°ΠΆΠ½ΡΡ Π΄Π΅ΡΠ°Π»ΠΈ. Π₯ΠΎΠ»ΡΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΡ ΡΠΎΠ·Π΄Π°Π΅ΠΌ, ΡΠ²ΡΠ·Π°Π½ Ρ ΡΠΎΠ΄ΠΈΡΠ΅Π»Π΅ΠΌ β ΠΌΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ Π΄Π΅ΡΠΊΡΠΈΠΏΡΠΎΡ ΠΎΠΊΠ½Π° ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ. Π Π΅ΠΆΠΈΠΌ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠΎΠ²ΠΊΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ xor (ΠΈΡΠΊΠ»ΡΡΠ°ΡΡΠ΅Π΅ ΠΈΠ»ΠΈ). ΠΡΠΎ ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ, ΡΡΠΎ ΠΏΠΈΠΊΡΠ΅Π»Ρ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΡ ΡΠΈΡΡΠ΅ΠΌ, β ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΡΡΡΡΡ Ρ ΠΏΠ΅ΡΠ²ΠΎΠ½Π°ΡΠ°Π»ΡΠ½ΡΠΌΠΈ ΠΏΠΈΠΊΡΠ΅Π»Π°ΠΌΠΈ Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ xor. ΠΠΎΠ³ΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ xor ΠΈΠΌΠ΅Π΅Ρ ΠΏΠΎΠ»Π΅Π·Π½ΡΡ ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎΡΡΡ. ΠΡΠ»ΠΈ ΠΡ ΠΏΡΠΈΠΌΠ΅Π½ΠΈΡΠ΅ Π΅Π΅ Π΄Π²Π°ΠΆΠ΄Ρ, ΠΡ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π». ΠΡΠΎΡ ΡΠ°ΠΌΡΠΉ ΡΡΠ°ΡΡΠΉ ΠΏΡΠΈΠ΅ΠΌ Π² ΠΊΠΎΠΌΠΏΡΡΡΠ΅ΡΠ½ΠΎΠΉ Π³ΡΠ°ΡΠΈΠΊΠ΅ β ΠΌΠ΅ΡΠΎΠ΄ ΠΏΡΠΎΡΡΠΎΠΉ Π°Π½ΠΈΠΌΠ°ΡΠΈΠΈ. ΠΡ ΡΠΈΡΡΠ΅ΡΠ΅ ΡΡΠΎ-ΡΠΎ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ xor ΡΠ΅ΠΆΠΈΠΌ ΠΈ ΡΡΠΈΡΠ°Π΅ΡΠ΅ ΠΏΡΠΎΡΡΡΠΌ ΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π΅Π³ΠΎ ΠΆΠ΅ ΡΠ½ΠΎΠ²Π° Π² xor ΡΠ΅ΠΆΠΈΠΌΠ΅. ΠΡΠ°ΠΊ, ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ ΠΊΠΎΠ΄ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ΅Π½ΠΈΡ, ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½Π½ΡΠΉ Π½ΠΈΠΆΠ΅.
void SplitController::LButtonDrag(POINTS pt) {
if (_hwnd.HasCapture()) {
// Erase previous divider and draw new one
UpdateCanvas canvas(_hwndParent);
ModeSetter mode(canvas, R2_NOTXORPEN);
canvas.Line(_dragX, 0, _dragX, _cy - 1);
_dragX = _dragStart + pt.x;
canvas.Line(_dragX, 0, _dragX, _cy - 1);
}
}
ΠΡ ΡΠΈΡΡΠ΅ΠΌ Π²Π΅ΡΡΠΈΠΊΠ°Π»ΡΠ½ΡΡ Π»ΠΈΠ½ΠΈΡ Π² xor ΡΠ΅ΠΆΠΈΠΌΠ΅, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ ΠΏΡΠ΅Π΄ΡΠ΄ΡΡΡΡ ΡΠΎΡ ΡΠ°Π½Π΅Π½Π½ΡΡ ΠΏΠΎΠ·ΠΈΡΠΈΡ. Π’Π°ΠΊ ΠΊΠ°ΠΊ ΡΡΠΎ ΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡ Π²ΠΎ Π²ΡΠΎΡΠΎΠΉ ΡΠ°Π·, ΠΌΡ ΡΠΈΡΡΠ΅ΠΌ ΡΡΡ Π»ΠΈΠ½ΠΈΡ Π² ΡΠΎΠΌ ΠΆΠ΅ ΡΠ°ΠΌΠΎΠΌ ΠΌΠ΅ΡΡΠ΅ ΠΈ, Π² ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ΅, Π±ΡΠ΄ΡΡ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½Ρ ΠΏΠ΅ΡΠ²ΠΎΠ½Π°ΡΠ°Π»ΡΠ½ΡΠ΅ ΠΏΠΈΠΊΡΠ΅Π»Ρ ΠΈΠ·-ΠΏΠΎΠ΄ ΡΡΠΎΠΉ Π»ΠΈΠ½ΠΈΠΈ. ΠΠ°ΡΠ΅ΠΌ ΠΌΡ ΡΠΈΡΡΠ΅ΠΌ Π½ΠΎΠ²ΡΡ Π»ΠΈΠ½ΠΈΡ Π² Π½ΠΎΠ²ΠΎΠΉ ΠΏΠΎΠ·ΠΈΡΠΈΠΈ, ΡΠ°ΠΊΠΆΠ΅ Π² xor ΡΠ΅ΠΆΠΈΠΌΠ΅. ΠΡ Π·Π°ΠΏΠΎΠΌΠΈΠ½Π°Π΅ΠΌ ΡΡΡ ΠΏΠΎΠ·ΠΈΡΠΈΡ, ΡΡΠΎΠ±Ρ Π² ΡΠ»Π΅Π΄ΡΡΡΠΈΠΉ ΡΠ°Π·, ΠΊΠΎΠ³Π΄Π° Π²ΡΠ·ΠΎΠ²Π΅ΡΡΡ LButtonDrag, ΠΌΡ ΠΌΠΎΠ³Π»ΠΈ ΡΡΠ΅ΡΠ΅ΡΡ Π΅Π΅ ΡΠ°ΠΊΠΆΠ΅. Π ΡΠ°ΠΊ Π΄Π°Π»Π΅Π΅, ΠΏΠΎΠΊΠ° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π½Π΅ ΠΎΡΠΏΡΡΡΠΈΡ ΠΊΠ½ΠΎΠΏΠΊΡ ΠΌΡΡΠΈ.
void SplitController::LButtonUp(POINTS pt) {
// Calling ReleaseCapture will send us the WM_CAPTURECHANGED
_hwnd.ReleaseMouse();
_hwndParent.SendMessage(MSG_MOVESPLITTER, _dragStart + pt.x);
}
Π ΡΡΠΎΠΉ ΡΠΎΡΠΊΠ΅ ΠΌΡ Π΄ΠΎΠ»ΠΆΠ½Ρ ΡΡΠ΅ΡΠ΅ΡΡ Π²Π΅ΡΡΠΈΠΊΠ°Π»ΡΠ½ΡΡ ΡΡΡΠΎΠΊΡ Π² ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠΉ ΡΠ°Π·. ΠΠ΄Π½Π°ΠΊΠΎ, ΠΌΡ Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ Π½Π΅ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²Π΅Π½Π½ΠΎ β ΠΌΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ Π·Π΄Π΅ΡΡ Π½Π΅Π±ΠΎΠ»ΡΡΠΎΠΉ ΠΏΡΠΈΠ΅ΠΌ. ΠΡ ΠΏΡΠ΅ΠΊΡΠ°ΡΠ°Π΅ΠΌ ΡΠ±ΠΎΡ Π΄Π°Π½Π½ΡΡ ΠΌΡΡΠΈ. ΠΠ°ΠΊ ΠΏΠΎΠ±ΠΎΡΠ½ΡΠΉ ΡΡΡΠ΅ΠΊΡ, Windows ΠΏΠΎΡΡΠ»Π°Π΅Ρ Π½Π°ΠΌ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ WM_CAPTURECHANGED. ΠΠΎ Π²ΡΠ΅ΠΌΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΡΡΠΎΠ³ΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ, ΠΌΡ ΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ ΠΈ ΡΡΠΈΡΠ°Π΅ΠΌ Π²Π΅ΡΡΠΈΠΊΠ°Π»ΡΠ½ΡΡ ΡΡΡΠΎΠΊΡ.
void SplitController::CaptureChanged() {
// We are losing capture
// End drag selection -- for whatever reason
// Erase previous divider
UpdateCanvas canvas(_hwndParent);
ModeSetter mode(canvas, R2_NOTXORPEN);
canvas.Line(_dragX, 0, _dragX, _cy - 1);
}
ΠΠΎΡΠ΅ΠΌΡ ΠΌΡ Π΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ ΡΠ°ΠΊΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ? ΠΠΎΡΠΎΠΌΡ, ΡΡΠΎ Windows ΠΌΠΎΠΆΠ΅Ρ Π·Π°ΡΡΠ°Π²ΠΈΡΡ Π½Π°Ρ, ΠΏΡΠ΅ΠΊΡΠ°ΡΠΈΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ Π΄Π°Π½Π½ΡΡ ΠΎΡ ΠΌΡΡΠΈ ΠΏΡΠ΅ΠΆΠ΄Π΅, ΡΠ΅ΠΌ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΎΠΏΡΡΡΠΈΡ Π΅Π΅ ΠΊΠ½ΠΎΠΏΠΊΡ. ΠΡΠΎ ΠΌΠΎΠΆΠ΅Ρ ΡΠ»ΡΡΠΈΡΡΡΡ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΊΠΎΠ³Π΄Π° Π΄ΡΡΠ³ΠΎΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎ ΡΠ΅ΡΠ°Π΅Ρ ΡΠ°ΡΠΏΠ°Ρ Π½ΡΡΡ Π΅Π³ΠΎ ΠΎΠΊΠ½ΠΎ, Π² ΡΠΎ Π²ΡΠ΅ΠΌΡ ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ Π² ΠΏΡΠΎΡΠ΅ΡΡΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ΅Π½ΠΈΡ. Π ΡΡΠΎΠΌ ΡΠ»ΡΡΠ°Π΅ Π½Π°ΡΠ΅ ΠΎΠΊΠ½ΠΎ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ ΠΏΠΎΠ»ΡΡΠΈΠ»ΠΎ Π±Ρ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΎΠ± ΠΎΡΠΆΠ°ΡΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΊΠΈ. ΠΡΠ»ΠΈ Π±Ρ ΠΌΡ Π½Π΅ Π±ΡΠ»ΠΈ ΡΠ°ΠΊ ΡΠΌΠ½Ρ, ΠΌΡ Π±Ρ Π½Π΅ Π±ΡΠ»ΠΈ ΡΠΏΠΎΡΠΎΠ±Π½Ρ ΡΠΈΡΡΠΎ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ°ΡΡΡΡ. Π ΡΡΠ°ΡΡΡΡ, ΠΏΠ΅ΡΠ΅Π΄ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ΠΌ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π΄Π°Π½Π½ΡΡ ΠΌΡΡΠΈ, Windows ΡΡΠΌΠ΅Π΅Ρ ΠΏΠΎΡΠ»Π°ΡΡ Π½Π°ΠΌ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ WM_CAPTURECHANGED, ΠΈ ΠΌΡ ΠΏΡΠΈΠΌΠ΅ΠΌ Π΅Π³ΠΎ ΠΊ ΡΠ²Π΅Π΄Π΅Π½ΠΈΡ, ΡΡΠΎΠ±Ρ ΡΠ΄Π΅Π»Π°ΡΡ Π½Π°ΡΡ ΠΎΡΠΈΡΡΠΊΡ.
ΠΠ΅ΡΠ½Π΅ΠΌΡΡ ΡΠ½ΠΎΠ²Π° ΠΊ LBUTTONUP β ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π·Π°ΠΊΠ°Π½ΡΠΈΠ²Π°Π΅Ρ ΠΏΠ΅ΡΠ΅ΠΌΠ΅ΡΠ΅Π½ΠΈΠ΅, ΠΌΡ ΠΏΠΎΡΡΠ»Π°Π΅ΠΌ ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ Π½Π°ΡΠ΅ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ MSG_MOVESPLITTER, ΠΏΠ΅ΡΠ΅Π΄Π°Π²Π°Ρ Π΅ΠΌΡ Π½ΠΎΠ²ΡΡ ΠΏΠΎΠ·ΠΈΡΠΈΡ ΡΠ΅Π½ΡΡΠ° ΠΏΠΎΠ»ΠΎΡΡ ΡΠ°ΡΡΠ΅ΠΏΠΈΡΠ΅Π»Ρ, ΠΈΠ·ΠΌΠ΅ΡΡΠ΅ΠΌΠΎΠΉ Π² ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠ°Ρ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΎΠΉ ΠΎΠ±Π»Π°ΡΡΠΈ ΡΠΎΠ΄ΠΈΡΠ΅Π»Ρ. ΠΡ ΡΠΆΠ΅ Π²ΠΈΠ΄Π΅Π»ΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΈΠΉ ΠΊΠΎΠ΄, ΡΠ΅Π°Π³ΠΈΡΡΡΡΠΈΠΉ Π½Π° ΡΡΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅.
ΠΠ΄Π΅ΡΡ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅.
// Reserved by Reliable Software Library
const UINT MSG_RS_LIBRARY = WM_USER + 0x4000;
// wParam = new position wrt parent's left edge
const UINT MSG_MOVESPLITTER = MSG_RS_LIBRARY + 1;
Π Π·Π°ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ ΡΡΠ°Π³ΠΌΠ΅Π½Ρ ΠΈΠ· ΠΎΡΠ΅Π½Ρ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ³ΠΎ ΠΊΠ»Π°ΡΡΠ° HWnd, ΠΊΠΎΡΠΎΡΡΠΉ ΠΈΠ½ΠΊΠ°ΠΏΡΡΠ»ΠΈΡΡΠ΅Ρ ΠΌΠ½ΠΎΠ³ΠΈΠ΅ Π±Π°Π·ΠΈΡΠ½ΡΡ ΡΡΠ½ΠΊΡΠΈΠΈ API Windows, ΠΈΠΌΠ΅ΡΡΠΈΠ΅ Π΄Π΅Π»ΠΎ Ρ ΠΎΠΊΠ½Π°ΠΌΠΈ. Π ΡΠ°ΡΡΠ½ΠΎΡΡΠΈ, ΡΠ°ΡΡΠΌΠΎΡΡΠΈΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ MoveDelayPaint ΠΈ ForceRepaint, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΠΈ Π² ΠΏΠ΅ΡΠ΅ΡΠΈΡΠΎΠ²ΠΊΠ΅ ΠΏΠΎΠ»ΠΎΡΠΊΠΈ ΡΠ°ΡΡΠ΅ΠΏΠΈΡΠ΅Π»Ρ.
class HWnd {
public:
void Update() {
::UpdateWindow(_hwnd);
}
// Moving
void Move(int x, int y, int width, int height) {
::MoveWindow(_hwnd, x, y, width, height, TRUE);
}
void MoveDelayPaint(int x, int y, int width, int height) {
::MoveWindow(_hwnd, x, y, width, height, FALSE);
}
// Repainting
void Invalidate() {
::InvalidateRect(_hwnd, 0, TRUE);
}
void ForceRepaint() {
Invalidate();
Update();
}
private:
HWND _hwnd;
};
ΠΠ°ΠΊ ΠΎΠ±ΡΡΠ½ΠΎ, ΠΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π·Π°Π³ΡΡΠ·ΠΈΡΡ ΠΏΠΎΠ»Π½ΡΠΉ ΠΈΡΡ ΠΎΠ΄Π½ΡΠΉ ΡΠ΅ΠΊΡΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, ΠΊΠΎΡΠΎΡΠΎΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΠΎΡΡ Π² ΡΡΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅.
ΠΠ°Π»Π΅Π΅: Π‘Π»Π΅Π΄ΡΡΡΠ°Ρ ΠΎΠ±ΡΡΠ°ΡΡΠ°Ρ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ° ΡΠ°ΡΡΠΊΠ°Π·ΡΠ²Π°Π΅Ρ ΠΎ ΡΠ°ΡΡΡΠ°Ρ .
Bitmaps
In this tutorial we'll learn how to load bitmaps from resources and from files, how to pass them around and blit them to the screen. We'll also see how to create and use an empty bitmap as a canvas, draw a picture on it and then blit it to the screen. Finally, we'll combine these techniques to write a simple program that uses double-buffering and timer messages to show a simple animation involving sprites.
First of all, in most cases Windows provides storage for bitmaps and takes care of the formatting of bits. The programmer gets access to the bitmap through a handle, whose type is HBITMAP. (Remember to set the STRICT flag when compiling Windows programs, to make sure HBITMAP is a distinct type, rather than just a pointer to void.)
Since a bitmap is a resource (in the Resource Management sense), the first step is to encapsulate it in a βstrong pointerβ type of interface. Notice the transfer semantics of the constructor and the overloaded assignment operator, characteristic of a resource that can have only one owner at a time.
We instruct Windows to release the resources allocated to the bitmap by calling DeleteObject.
class Bitmap {
public:
Bitmap() : _hBitmap (0) {}
// Transfer semantics
Bitmap(Bitmap& bmp) : _hBitmap(bmp.Release()) {}
void operator=(Bitmap& bmp) {
if (bmp._hBitmap != _hBitmap) {
Free();
_hBitmap = bmp.Release();
}
}
HBITMAP Release() {
HBITMAP h = _hBitmap;
_hBitmap = 0;
return h;
}
~Bitmap() {
Free();
}
// implicit conversion for use with Windows API
operator HBITMAP() {
return _hBitmap;
}
protected:
Bitmap(HBITMAP hBitmap) : _hBitmap(hBitmap) {}
void Free() {
if (_hBitmap) ::DeleteObject(_hBitmap);
}
HBITMAP _hBitmap;
};
Now that the management issues are out of the way, we can concentrate on loading bitmaps. The simplest way to include a bitmap in your program is to add it to the resource file. In the resource editor of your development environment you can create new bitmaps or import them from external files. You can either give them names (strings) or numerical ids. When you want to access such a bitmap in your program you have to load it from the resources. Here are two methods that do just that. You have to give them a handle to the program instance.
void Bitmap::Load(HINSTANCE hInst, char const * resName) {
Free();
_hBitmap = (HBITMAP)::LoadImage(hInst, resName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (_hBitmap == 0) throw WinException("Cannot load bitmap from resources", resName);
}
void Bitmap::Load(HINSTANCE hInst, int id) {
Free();
_hBitmap = (HBITMAP)::LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (_hBitmap == 0) throw WinException("Cannot load bitmap from resources");
}
Loading a bitmap directly from a file is also very simple and can be done using the same API, LoadImage. Remember, it will only work if the file is a Windows (or OS/2) bitmap β such files usually have the extension .bmp. There is no simple way of loading other types of graphics files, .gif, .jpg, .png, etc. You have to know their binary layout and decode them explicitly (there are other web sites that have this information).
void Bitmap::Load(char* path) {
Free();
_hBitmap = (HBITMAP)::LoadImage(0, path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if(_hBitmap == 0) throw WinException("Cannot load bitmap from file", path);
}
Once you got hold of a bitmap, you may want to enquire about its dimensions. Here's how you do it.
void Bitmap::GetSize(int& width, int& height) {
BITMAP bm;
::GetObject(_hBitmap, sizeof(bm), &bm);
width = bm.bmWidth;
height = bm.bmHeight;
}
Finally, you might want to create an empty bitmap and fill it with your own drawings programmatically. You have to specify the dimensions of the bitmap and you have to provide a device context (Canvas) for which the bitmap is targeted. Windows will create a different type of bitmap when your target is a monochrome monitor or printer, and different when it's a graphics card set to True Color. Windows will create a bitmap that is compatible with the target device.