Нотатки програмістера Як створити власнийкомпонент у swing
IT – це чудово!
Як створити власний компонент у swing

Введення в Swing у тезах
Важкі та легкі компоненти
Подвійна буферизація
У Swing за замовчуванням використовується подвійна буферизація. Це означає, що весь процес відтворення компонента відбувається на невидимому полотні (буфері). Після завершення процесу відтворення компонента його готове зображення копіюється на видиме полотно (виводиться на екран). Подвійна буферизація дозволяє уникнути мерехтіння зображення під час малювання компонента.
Для економії ресурсів другий буфер не заводиться для кожного компонента окремо. Натомість існує єдиний буфер, керований RepaintManager-ом. Для відключення подвійної буферизації в усьому додатку використовується метод RepaintManager.setDoubleBufferingEnabled(false) . Подвійну буферизацію можна відключати для конкретних компонентів методом setDoubleBuffered(false). Настільки не розумний на перший (і другий :)) погляд хід, найчастіше потрібно при налагодженні програми.
Базовий компонент JComponent та механізм малювання.
Усі компоненти Swing успадковуються від JComponent. Цей базовий клас реалізує механізм малювання легковажних компонентів.
Процес відмальовування компонента починається з виклику операційною системою методу paint() великовагового компонента. Далі, виклик методу paint() відбувається всім вкладених у нього компонентів.
Як би не свербіли руки, перевизначити метод paint, робити цього не варто!
На першому етапі методу paint() визначається поточний об'єкт RepaintManager, у якого запитується інформація про використання подвійної буферизації. У разі її використання виходить буфер. Далі обчислюється прямокутник відсікання (cliprectangle) за аргументами, переданими операційній системі батьківського важкого компонента.
При включеній подвійній буферизації викликається метод paintDoubleBuffered(), в якому відбувається налаштування позаекранного буфера: виходить зображення необхідного розміру, для нього створюється об'єкт Graphics і викликається метод paintWithOffScreenBuffer(), який ініціює безпосередньо промальовування компонента, що відбувається в три етапи.
Першому етапу відповідає метод paintComponent() . Саме цей метод відповідає за логіку відтворення компонента. Важливою особливістю перевизначення саме цього методу, а не методу paint(), є те, що перевизначаючи метод paintComponent ви позбавляєте себе завдань оптимізації виведення графіки і відмальовування вкладених компонентів. Перевизначення методу paintComponent - розв'язання задачі в лоб. Елегантніше рішення - реалізація UI представника для нового компонента, але цей товариш залишиться за рамками цієї статті. Щоб зрозуміти яку роль цей об'єкт грає у малюванні компонента, достатньо зазирнути у вихідний код методу paintComponent:
Наступним етапом йде малювання рамки компонента методом paintBorder() . Цей метод використовує поле border компонент для малювання рамки і не вимагає перевизначення. Єдиним нюансом тут є той факт, що рамка малюється поверх результатів праці методу paintComponent. Тому при малюванні компонента в paintComponent варто враховувати наявність/відсутність рамки у компонента та її товщину.
Завершальним етапом є відмальовування вкладених компонентів у методі paintChildren() . Сенс у перевизначенні цього методу не більше, ніж у перевизначенні методу paint.

Налагодження графіки
У swing є чудовий засіб дляналагодження процесу малювання, клас DebugGraphics. Він є обгорткою над Graphics і дозволяє контролювати процес малювання.
DebugGraphics надає можливість виведення інформації про виконувані операції, уповільнення процесу зображення (для цього потрібно вимкнення подвійної буферизації), дублювання процесу зображення в окремому вікні. Для включення налагодження малювання викликається метод setDebugGraphicsOptions(int) у компонента, чий процес малювання ви хочете налагодити.Слід зазначити, що налагодження буде так само включено для всіх вкладених компонентів.
Режими налагодження задані у статичних константах класу DebugGraphics:
Безпосередніх інструкцій щодо створення компонента наводити сенсу не бачу, все й так досить зрозуміло: створюємо клас, успадковуємо його від одного з існуючих компонентів, перевизначаємо алгоритм відтворення у методі paintComponent (не забуваємо враховувати можливість додавання рамки), створюємо необхідні події, з гордістю використовуємо свій новий компонент.
Вибір батьківського компонента залежить від конкретного компонента, що розробляється. Якщо вам не потрібна функціональність існуючих компонентів, успадковуйте від JComponent. Це очевидно.
Для створення нових подій просто перехопіть відповідні базові та доповніть їх логікою генерування власних. Наприклад, якщо ви розробляєте компонент, що представляє собою таблицю, і хочете генерувати подію натискання мишею по комірці, перехопіть подію натискання миші на вашому компоненті, обчисліть комірку за координатами, отриманими з аргументів перехопленої події, створіть власні аргументи з індексами комірки та сповістите тому, що по осередку відбулося клацання.