實際上,如果百度“字幕遮擋器,很可以找到一些結果,但多半是不透明的,不符合我的使用需要,再者自己寫這種小工具是很有趣的學習過程。這個學習過程中有一些心得,不得不記錄一二。
程序用途
對字幕進行遮擋(學習英語用)
在網頁中對一段文字加上底色,提高閱讀時的註意力程度(個人需求)
兩種用途如下圖所示
功能要求
根據程序的用途可以看出,該程序必須實現以下功能:
半透明窗體
總在最前
大小調整
拖動
關閉
後三個功能實際上都是因為無標題,所以需要自己實現。此外,還有一些錦上添花的功能:
顏色選擇(包括不透明度的調節)
切換是否總在最前
記憶顏色與位置
防止窗口縮得過小而無法找到
後來在編程實現的過程中也會按這些功能來描述。
編程實現
語言: Java
程序的功能並不復雜,因此結構上也偷了些懶。一個主類Cover
JFrame
的CoverFrame
。這裏都是一些很定式的寫法,沒什麽特別的
public class Cover {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
CoverFrame frame = new CoverFrame();
...
}
});
}
}
class CoverFrame extends JFrame {
...
}
程序的各項主要功能基本上是在CoverFrame
半透明窗體
半透明窗體的關鍵是先要去掉窗體的標題和邊框,然後給該Frame設置半透明背景色即可。
class CoverFrame extends JFrame { ... private Color color = new Color(0, 0, 0, 200); //半透明 ... public CoverFrame() { ... setUndecorated(true); //去掉邊框 ... setBackground(color); ... getContentPane().setBackground(color); } }
ADVERTISEMENT
這部分比較簡單,不過值得一說的是,如果窗體將保持半透明,即窗體不會被設置成不透明色的話(因為後面加入了顏色選擇,用戶完全可能選擇完全不透明的顏色),只要對CoverFrame
對象setBackground(color)
即可。
但一旦選擇了完全不透明的顏色(Alpha值為255),窗口則會變為默認的灰色。避免這種情況,就需要把Frame的ContentPane也設置成相同顔色getContentPane().setBackground(color)
。
總在最前
想要窗體總在最前也比較簡單,有一個現成的函數setAlwaysOnTop
來控制。要讓程序能切換是否總在最前,也只要在CoverFrame中設置一個布爾型的state,作為是否總在最前的開關,並添加一個JCheckBoxMenuItem
到窗口的JPopupMenu
class CoverFrame extends JFrame {
...
private JPopupMenu popupMenu = new JPopupMenu(); //右鍵菜單
private Color color = new Color(0, 0, 0, 200);
private boolean onTop = true; //默認總在最前
...
public CoverFrame() {
setAlwaysOnTop(onTop);
...
CoverFrame that = this;
// set up popup menus
...
JMenuItem topItem = new JCheckBoxMenuItem("Always On Top", true); //帶勾選框,默認勾選
topItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
onTop = !onTop;
setAlwaysOnTop(onTop); //改變當前狀態
}
});
popupMenu.add(topItem);
...
}
}
拖動與大小調整
這兩個功能本來應該是一個窗體固有的,但因為把標題與邊框都去掉了,現在都需要自己來實現。因為兩個功能的代碼犬牙交錯,所以放在一起來講了。
拖動的原理是,點擊時記錄點擊位置(相對於窗口原點),拖動時獲得鼠標在屏幕上的絕對位置,這一位置減去之前記錄的相對點擊位置,就是新的窗口的位置了,這樣就實現了窗口的拖動功能。
大小調整的思路則是判斷點擊位置是處於窗口的邊緣位置,如果是,改變鼠標指針。如果位置處於左側或者上方,拖動裏改變寬/高,並改變窗口位置,如果在右側或者正文,拖動時改變窗口的寬/高。
class CoverFrame extends JFrame {
private Point point = new Point(0, 0); //用於保存點擊位置
...
public CoverFrame() {
...
addMouseListener(new MouseAdapter() { //監聽鼠標點擊
public void mousePressed(MouseEvent event) {
// record the point where you begin to drag
point = event.getPoint(); //記錄點擊位置
popupEvent(event); //右鍵菜單
}
public void mouseReleased(MouseEvent event) {
popupEvent(event);
}
private void popupEvent(MouseEvent event) {
if (event.isPopupTrigger()) {
popupMenu.show(event.getComponent(), event.getX(),
event.getY()); //在右鍵位置顯示菜單
}
}
} );
addMouseMotionListener(new MouseMotionListener() {
// 用來標識點擊區域(上下左右)
private boolean top = false;
private boolean down = false;
private boolean left = false;
private boolean right = false;
final private int GAP = 3;
public void mouseMoved(MouseEvent event) {
//窗體的寬高
int width = getWidth();
int height = getHeight();
//點擊位置(相對)
int x = event.getX();
int y = event.getY();
top = false;
down = false;
left = false;
right = false;
if (Math.abs(y) <= GAP) {
top = true;
} else if (Math.abs(y-height) <=GAP) {
down = true;
}
if (Math.abs(x) <= GAP) {
left = true;
} else if (Math.abs(x-width) <=GAP) {
right = true;
}
//如果判斷在邊緣就改變鼠標指針
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if (top || down)
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
if (left || right)
setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
if ((left && top) || (right && down))
setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
if ((right && top) || (left && down))
setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
}
public void mouseDragged(MouseEvent event) {
bounds = getBounds();
if (!(top || down || left || right)) {
// 在中間拖動窗口
Point absPoint = event.getLocationOnScreen();
// set the location of window relate to where you click
absPoint.translate(-(int)point.getX(),
-(int)point.getY());
setLocation(absPoint);
} else {
//在四角縮放窗體
if (top) {
bounds.setLocation((int)bounds.getX(), (int)bounds.getY() + event.getY());
bounds.setSize((int)bounds.getWidth(), (int)bounds.getHeight() - event.getY());
}
if (down) {
bounds.setSize((int)bounds.getWidth(), event.getY());
}
if (left) {
bounds.setLocation((int)bounds.getX() + event.getX(), (int)bounds.getY());
bounds.setSize((int)bounds.getWidth() - event.getX(), (int)bounds.getHeight());
}
if (right) {
bounds.setSize(event.getX(),(int)bounds.getHeight());
}
validateBounds();
setBounds(bounds);
}
}
} );
關閉與保存設置
關閉本來其實是沒啥說的,就算是沒有標題欄,但是因為把顏色和位置信息記錄下來,還是有一些要註意的地方。
一般通過按鍵關閉窗口,會調用dispose
函數,但是這樣的話,並不會觸發windowClose的事件。要主動發出這一事件才可以。
顏色修改
檢查窗口大小
總結
Tags: CoverFrame 功能 窗體 透明 程序 遮擋
文章來源: