乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Java Swing讀書筆記之二 (Java極富客戶端效果開發(fā))

       fenyu8 2011-07-17
      12.  明確的告訴java 2d你將要完成的繪制,而不是使用一個更為通用的方式,這樣能夠帶來更好的性能。
       1     //畫線的bad way
      2 Shape line = new Line2D.Double(LINE_X, BAD_Y, LINE_X + 50, BAD_Y + 50);
      3 g2d.draw(line);
      4
      5 //畫線的good way
      6 g.drawLine(LINE_X, GOOD_Y, LINE_X + 50, GOOD_Y + 50);
      7
      8 //畫rectangle的bad way
      9 Shape rect = new Rectangle(RECT_X, BAD_Y, 50, 50);
      10 g2d.fill(rect);
      11
      12 //畫rectangle的good way
      13 g.fillRect(RECT_X, GOOD_Y, 50, 50);

       

      13.  圖像合成,其中最為有用的三個規(guī)則分別是clear、SrcOver(swing缺省)和SrcIn。
             Clear:是擦掉一個圖像的背景以便使他變得完全透明的一個容易的方式,可以將其理解為Photoshop中的橡皮擦,通過Clear可以清除任意形狀的區(qū)域。

       1     public void exampleForClear() {
      2 BufferedImage image = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
      3 Graphics2D g2 = image.createGraphics();
      4 //draw something here.
      5 //...
      6 //Erase the content of the image.
      7 g2.setComposite(AlphaComposite.Clear);
      8 //The color,the Paint, etc. do not matter
      9 g2.fillRect(0,0,image.getWidth(),image.getHeight());
      10 }

             SrcOver: 其運算公式為Ar = As + Ad * (1 - As), Cr = Cs + Cd * (1 - As), 其中Ar為結(jié)果Alpha,As表示源圖像的Alpha,As為目的圖像的Alpha,Cr表示(RGB)中每個通道的結(jié)果值,Cs為源圖像中(RGB)單個通道的值,Cd為目的圖像的單個通道值。
             一般的用法為在目的圖像上繪制半透明的源圖像。
             SrcIn:位于目的地內(nèi)部的那部分源代替目的地,位于目的地之外的那部分源丟棄掉。

       1     protected void paintComponent(Graphics g) {
      2 BufferedImage temp = new BufferedImage(getWidth(), getHeight(),
      3 BufferedImage.TYPE_INT_ARGB);
      4 Graphics2D g2 = temp.createGraphics();
      5
      6 if (shadow.isSelected()) {
      7 int x = (getWidth() - image.getWidth()) / 2;
      8 int y = (getHeight() - image.getHeight()) / 2;
      9 g2.drawImage(image, x + 4, y + 10, null);
      10
      11 Composite oldComposite = g2.getComposite();
      12 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.75f));
      13 g2.setColor(Color.BLACK);
      14 g2.fillRect(0, 0, getWidth(), getHeight());
      15 g2.setComposite(oldComposite);
      16 g2.drawImage(image, x, y, null);
      17 } else {
      18 int x = (getWidth() - image.getWidth()) / 2;
      19 int y = (getHeight() - image.getHeight()) / 2;
      20 g2.drawImage(image, x, y, null);
      21
      22 Composite oldComposite = g2.getComposite();
      23 g2.setComposite(AlphaComposite.SrcIn);
      24 x = (getWidth() - landscape.getWidth()) / 2;
      25 y = (getHeight() - landscape.getHeight()) / 2;
      26 g2.drawImage(landscape, x, y, null);
      27 g2.setComposite(oldComposite);
      28 }
      29
      30 g2.dispose();
      31 g.drawImage(temp, 0, 0, null);
      32 }

       

      14.  利用漸變完成的反射效果,主要分為3個步驟完成,見下例:

       1     private BufferedImage createReflection(BufferedImage image) {
      2 int height = image.getHeight();
      3
      4 BufferedImage result = new BufferedImage(image.getWidth(), height * 2,
      5 BufferedImage.TYPE_INT_ARGB);
      6 Graphics2D g2 = result.createGraphics();
      7 //1. 想渲染正常物體一樣渲染它。
      8 g2.drawImage(image, 0, 0, null);
      9
      10 //2. 渲染這個物體上下顛倒的一個副本
      11 g2.scale(1.0, -1.0);
      12 g2.drawImage(image, 0, -height - height, null);
      13 g2.scale(1.0, -1.0);
      14
      15 // Move to the origin of the clone
      16 g2.translate(0, height);
      17
      18 //3. 模糊這個副本的一部分以使它淡出,隨著它遠離最初的物體。
      19 GradientPaint mask;
      20 //目的顏色RGB無關(guān)重要,alpha值必須為0。
      21 mask = new GradientPaint(0, 0, new Color(1.0f, 1.0f, 1.0f, 0.5f),
      22 0, height / 2, new Color(1.0f, 1.0f, 1.0f, 0.0f));
      23 Paint oldPaint = g2.getPaint();
      24 g2.setPaint(mask);
      25 // Sets the alpha composite
      26 g2.setComposite(AlphaComposite.DstIn);
      27 //盡量覆蓋全部顛倒圖像,以避免因覆蓋不全而造成的偽影。
      28 g2.fillRect(0, 0, image.getWidth(), height);
      29 g2.dispose();
      30 return result;
      31 }

       

      15.  線性漸變LinearGradientPaint(float startX,float startY,float endX,float endY,float[] fractions,Color[] colors),這里包含兩個數(shù)組參數(shù),其中第一個float類型的數(shù)組包含漸變中使用的每個顏色的位置。每一對位置/顏色被稱為一個停頓,見下例:

       1     protected void paintComponent(Graphics g) {
      2 Graphics2D g2 = (Graphics2D) g;
      3 Paint oldPaint = g2.getPaint();
      4 LinearGradientPaint p;
      5
      6 p = new LinearGradientPaint(0.0f, 0.0f, 0.0f, 20.0f,
      7 new float[] { 0.0f, 0.5f, 0.501f, 1.0f },
      8 new Color[] { new Color(0x63a5f7),
      9 new Color(0x3799f4),
      10 new Color(0x2d7eeb),
      11 new Color(0x30a5f9) });
      12 g2.setPaint(p);
      13 g2.fillRect(0, 0, getWidth(), 21);
      14 g2.setPaint(oldPaint);
      15 super.paintComponent(g);
      16 }

       

      16.  優(yōu)化漸變的3個技巧:

            1) 緩存這個漸變:該解決方案是把這個漸變變成一個圖像并僅僅繪制那個圖像,但是缺點是需要消耗更多的內(nèi)存。

       1     protected void paintComponent(Graphics g) {
      2 if (gradientImage == null
      3 || gradientImage.getWidth() != getWidth()
      4 || gradientImage.getHeight() != getHeight()) {
      5 gradientImage = new BufferedImage(getWidth(),getHeigth(),BufferedImage.TYPE_INT_RGB);
      6 Graphics2D g2d = (Graphics2D)gradientImage.getGraphics();
      7 g2d.setPaint(backgroundGradient);
      8 g2d.fillRect(0,0,getWidth(),getHeight());
      9 g2d.dispose()
      10 }
      11 g.drawImage(gradientImage,0,0,null);
      12 }

            2) 更巧妙的緩存:當繪制一個垂直或者水平漸變時,每一列或者每一行都是相同的,因此可以只是保留一列或者一行的數(shù)據(jù),然在需要覆蓋漸變時在拉伸該列或者該行。

       1     protected void paintComponent(Graphics g) {
      2 if (gradientImage == null || gradientImage.getHeight() != getHeight()) {
      3 gradientImage = MineCompatible.createCompatibleImage(1,getHeight());
      4 Graphics2D g2d = (Graphics2D)gradientImage.getGraphics();
      5 g2d.setPaint(backgroundGradient);
      6 g2d.fillRect(0,0,1,getHeight());
      7 g2d.dispose();
      8 }
      9 g.drawImage(gradientImage,0,0,getWidth(),getHeigth(),null);
      10 }

            3) 使用循環(huán)漸變的優(yōu)化:如果漸變只是被覆蓋組件高度的一半時,如以下代碼:

      1     protected void paintComponent(Graphics g) {
      2 Graphics2D g2d = (Graphics2D)g.createGraphics();
      3 g2d.setPaint(new GradientPaint(0.0f,0.0f,Color.WHITE,0.0f,getHeigth()/2.0f,Color.DARK_GRAY);
      4 g2d.fillRect(0,0,getWidth(),getHeight());
      5 }

            該代碼將會從組件的(0,0)到(0,height/2)繪制漸變,同時利用這個漸變的最后顏色填充剩下的像素,為了做到這一點,java 2d將不斷的檢查是否當前的像素位于這個漸變區(qū)域的外面,因此對于成千上萬的像素來說,將會花費很多時間。如果使用循環(huán)漸變的方式,java 2d內(nèi)部在渲染的時候?qū)贿M行該判斷,從而大大提高了整體的效率,見如下代碼:

      1     //循環(huán)GradientPaint
      2 new GradientPaint(new Point(0,0),Color.WHITE,new Point(0,getHeight())
      ,Color.DARK_GRAY,
      true/*該標志表示循環(huán)*/);
      3 //循環(huán)LinearGradientPaint
      4 new LinearGradientPaint(new Point(0,0),new Point(0,getHeigth())
      ,
      new float[] {0.0f,1.0f},new Color[] {Color.WHITE,Color.DARK_GRAY}
      ,MultipleGradientPaint.CycleMethod.REPEAT);

      17. 圖像處理:
           1) AffineTransformOp

      1     public BufferedImage makeeAffineTransformOp(BufferedImage srcImage) {
      2 //高度和寬度均為源圖像的50%。
      3 AffineTransform transform = AffineTransform.getScaleInstance(0.5, 0.5);
      4 AffineTransformOp op = new AffineTransformOp(transform,AffineTransformOp.TYPE_BILINEAR);
      5 return op.filter(srcImage,null);
      6 }

           2) RescaleOp

      1     private BufferedImage makeRescaleOp(BufferedImage srcImage) {
      2 BufferedImage dstImage = null;
      3 float[] factors = new float[] { 1.4f, 1.4f, 1.4f };
      4 float[] offsets = new float[] { 0.0f, 0.0f, 30.0f };
      5 //RGB每個顏色通道的亮度增加40%,B通道增加30/256=12%的顏色分量。
      6 RescaleOp op = new RescaleOp(factors, offsets, null);
      7 return op.filter(srcImage,null);
      8 }

       

      18. 玻璃窗格的基本繪制技巧:
           1) 給當前JFrame安裝玻璃窗格,安裝后該玻璃窗格的缺省顯示方式是隱藏顯示,即setVisible(false),如果之前JFrame已經(jīng)使用了玻璃窗格,本次操作只是替換一個新的對象,那么該窗格的visible屬性將和原有窗格的visible屬性保持一致。

      1     public ApplicationFrame() { //ApplicationFrame為應(yīng)用程序的主窗體,繼承自JFrame
      2 initComponents();
      3 //安裝玻璃窗格,glassPane是JComponent的子類。
      4 setGlassPane(glassPane = new ProgressGlassPane());
      5 }

           2) 實現(xiàn)玻璃窗格的paintComponent方法

       1     protected void paintComponent(Graphics g) {
      2 // enables anti-aliasing
      3 Graphics2D g2 = (Graphics2D) g;
      4 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
      5 RenderingHints.VALUE_ANTIALIAS_ON);
      6
      7 // gets the current clipping area
      8 Rectangle clip = g.getClipBounds();
      9
      10 // sets a 65% translucent composite
      11 AlphaComposite alpha = AlphaComposite.SrcOver.derive(0.65f);
      12 Composite composite = g2.getComposite();
      13 g2.setComposite(alpha);
      14
      15 // fills the background
      16 g2.setColor(getBackground());
      17 g2.fillRect(clip.x, clip.y, clip.width, clip.height);
      18 // centers the progress bar on screen
      19 FontMetrics metrics = g.getFontMetrics();
      20 int x = (getWidth() - BAR_WIDTH) / 2;
      21 int y = (getHeight() - BAR_HEIGHT - metrics.getDescent()) / 2;
      22
      23 // draws the text
      24 g2.setColor(TEXT_COLOR);
      25 g2.drawString(message, x, y);
      26 // goes to the position of the progress bar
      27 y += metrics.getDescent();
      28 // computes the size of the progress indicator
      29 int w = (int) (BAR_WIDTH * ((float) progress / 100.0f));
      30 int h = BAR_HEIGHT;
      31
      32 // draws the content of the progress bar
      33 Paint paint = g2.getPaint();
      34
      35 // bar's background
      36 Paint gradient = new GradientPaint(x, y, GRADIENT_COLOR1, x, y + h
      , GRADIENT_COLOR2);
      37 g2.setPaint(gradient);
      38 g2.fillRect(x, y, BAR_WIDTH, BAR_HEIGHT);
      39
      40 // actual progress
      41 gradient = new LinearGradientPaint(x, y, x, y + h,GRADIENT_FRACTIONS
      , GRADIENT_COLORS);
      42 g2.setPaint(gradient);
      43 g2.fillRect(x, y, w, h);
      44 g2.setPaint(paint);
      45
      46 // draws the progress bar border
      47 g2.drawRect(x, y, BAR_WIDTH, BAR_HEIGHT);
      48 g2.setComposite(composite);
      49 }

             3) 主窗體中的工作線程需要調(diào)用的方法,以便更新進度條的顯示狀態(tài)

       1     public void setProgress(int progress) {
      2 int oldProgress = this.progress;
      3 this.progress = progress;
      4
      5 // computes the damaged area
      6 FontMetrics metrics = getGraphics().getFontMetrics(getFont());
      7 int w = (int) (BAR_WIDTH * ((float) oldProgress / 100.0f));
      8 int x = w + (getWidth() - BAR_WIDTH) / 2;
      9 int y = (getHeight() - BAR_HEIGHT) / 2;
      10 y += metrics.getDescent() / 2;
      11
      12 w = (int) (BAR_WIDTH * ((float) progress / 100.0f)) - w;
      13 int h = BAR_HEIGHT;
      14 //The reason why uses the following repaint(x, y, w, h) not repaint() is to
      15 //avoid repainting all the area to improve the performance.
      16 repaint(x, y, w, h);
      17 }

      19.  玻璃窗格中屏蔽輸入事件,上例中繪制的玻璃窗格只是完成了基本的顯示效果,用戶仍然可以操作玻璃窗格覆蓋下的控件,這樣會給用戶帶來非常迷惑的感覺,因此需要屏蔽玻璃窗格覆蓋下的控件獲取來自鼠標和鍵盤的事件。
            1) 為玻璃窗格控件自身添加空的鼠標和鍵盤的監(jiān)聽器

      1     public ProgressGlassPane() {
      2 // blocks all user input
      3 addMouseListener(new MouseAdapter() { });
      4 addMouseMotionListener(new MouseMotionAdapter() { });
      5 addKeyListener(new KeyAdapter() { });
      6 }

            2) 以上操作只是較好的屏蔽了鼠標事件,但是對于鍵盤事件,由于swing將鍵盤事件直接發(fā)送到當前聚焦的控件,因此如果有一組控件已經(jīng)獲取了焦點,它仍然可以收到鍵盤按鍵事件,甚至可以通過tab或ctrl+tab在各個控件之間切換焦點。要完成該功能,需要在玻璃窗體變成可見時調(diào)用requestFocusInWindow()以奪取焦點,因此該段代碼仍然需要放在該對象的構(gòu)造函數(shù)中,如下:

       1     public ProgressGlassPane() {
      2 // blocks all user input
      3 addMouseListener(new MouseAdapter() { });
      4 addMouseMotionListener(new MouseMotionAdapter() { });
      5 addKeyListener(new KeyAdapter() { });
      6
      7 //This event will be triggered when this component turn to be visible.
      8 addComponentListener(new ComponentAdapter() {
      9 public void componentShown(ComponentEvent evt) {
      10 requestFocusInWindow();
      11 }
      12 });
      13 }

             3) 此時用戶仍然可以通過tab鍵將焦點傳入玻璃窗格覆蓋的控件中,因此需要在構(gòu)造函數(shù)中調(diào)用setFocusTraversalKeysEnabled(false)以便禁用該功能。

       1     public ProgressGlassPane() {
      2 // blocks all user input
      3 addMouseListener(new MouseAdapter() { });
      4 addMouseMotionListener(new MouseMotionAdapter() { });
      5 addKeyListener(new KeyAdapter() { });
      6
      7 setFocusTraversalKeysEnabled(false);
      8 //This event will be triggered when this component turn to be visible.
      9 addComponentListener(new ComponentAdapter() {
      10 public void componentShown(ComponentEvent evt) {
      11 requestFocusInWindow();
      12 }
      13 });
      14 }

       

      20.  屏蔽玻璃窗格中部分區(qū)域的鼠標事件,比如在一個完全透明的窗格中的左下角繪制一個公司的logo,其他部分則完全透明,此時,如果用戶將鼠標放到玻璃窗格下面的控件上方時,由于JFrame的最頂層組件是玻璃窗格,因此他攔截了鼠標光標的顯示效果,比如其下擺放了一組輸入框,如果沒有玻璃窗格,那么當鼠標停留在控件上方時,swing會根據(jù)實際控件的類型更新鼠標光標的形狀。此時由于玻璃窗格的存在,swing將無法在完成此項功能,因此我們需要為玻璃窗格組件重載public boolean contains(int x,int y)方法,以便通知swing框架,哪些x,y值不包含在玻璃窗格的攔截范圍之內(nèi),見如下代碼:

       1     @Override
      2 public boolean contains(int x, int y) {
      3 //when none of mouse events exist
      4 if (getMouseListeners().length == 0 &&
      5 getMouseMotionListeners().length == 0 &&
      6 getMouseWheelListeners().length == 0 &&
      7 getCursor() == Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)) {
      8 if (image == null) {
      9 return false;
      10 } else {
      11 int imageX = getWidth() - image.getWidth();
      12 int imageY = getHeight() - image.getHeight();
      13
      14 // if the mouse cursor is on a non-opaque(transparent) pixel
      // , mouse events
      are allowed
      16 int inImageX = x - imageX;
      17 int inImageY = y - imageY;
      18
      19 if (inImageX >= 0 && inImageY >= 0 &&
      20 inImageX < image.getWidth() && inImageY < image.getHeight()) {
      21 int color = image.getRGB(inImageX, inImageY);
      22 //it must be transparent if alpha is 0.
      23 return (color >> 24 & 0xFF) > 0;
      24 }
      25 return x > imageX && x < getWidth() && y > imageY && y < getHeight();
      26 }
      27 }
      28 return super.contains(x, y);
      29 }

      21.  分層窗格:JLayoutPane組件是swing的一個容器,是一個容納幾個子層的面板,swing框架依賴一個分層窗格以顯示必須橫跨其他組件的特定組件。分層窗格的每一層都通過一個整數(shù)來識別,這個整數(shù)定義為在這個層的堆棧的深度。最大值表示這個堆棧的最高層次,即顯示層的最上方。JLayerPane提供幾個層標識符以便容易的把組件插入到正確的層。
            JLayeredPane.DEFAULT_LAYER = 0;     一般放置按鈕和表格等正規(guī)組件。
            JLayeredPane.PALETTE_LAYER = 100;    一般用于面板和浮動工具欄。
            JLayeredPane.MODAL_LAYER = 200;        模式對話框。
            JLayeredPane.POPUP_LAYER = 300;        顯示彈出式窗口,包括工具提示、組合框下拉列表、框架菜單和上下文菜單。
            JLayeredPane.DRAG_LAYER = 400;        用于顯示拖拽操作過程中的項。
            swing用間隔100的單位設(shè)置這些層,以便使用者可以在他們之間容易的插入自己的層而不引起問題。具體插入方法如下:

      1     private void addLayeredComponent() {
      2 MyComponent validator = new MyComponent();
      3 JLayeredPane layeredPane = getRootPane().getLayeredPane();
      4 //分層組件需要使用OverlayLayout布局管理器,或者使用自定義的管理器才能讓該層的組件正確的顯示
      5 layeredPane.setLayout(new OverlayLayout(layeredPane));
      6 layeredPane.add(validator, (Integer)(JLayeredPane.DEFAULT_LAYER + 50));
      7 }

            如果JLayeredPane使用了普通的布局管理器,該管理器將不會考慮JLayeredPane中各個組件的層級關(guān)系,而是簡單的將他們視為同一層級,并且繼續(xù)按照該管理器既有的布局邏輯管理所有的組件,即便他們位于JLayeredPane的不同層級。

       1     private void loadImagesInLayers() {
      2 layeredPane.setLayout(new FlowLayout());
      3 for (int i = 2; i <= 5; i++) {
      4 String name = "images/photo" + i + ".jpg";
      5 URL url = getClass().getResource(name);
      6 Icon icon = new ImageIcon(url);
      7 JLabel label = new JLabel(icon);
      8 layeredPane.add(label,(Integer)(JLayeredPane.DEFAULT_LAYER + (i - 1) * 2));
      9 }
      10 }

       

      22.  重繪管理器(RepaintManager):在Swing的框架中只存在一個RepaintManager,可以通過RepaintManager的靜態(tài)方法currentManager獲取,用戶也可以根據(jù)自己的需要自定義一個RepaintManager的子類,同時通過setCurrentManager方法設(shè)置新的RepaintManager。該類主要用于攔截所有swing組件通過repaint方法刷新組件的顯示區(qū)域,該類在攔截并處理后,在交給EDT繼續(xù)處理,因此有些特殊的效果需要通過重載RepaintManager才能很好的完成。如下代碼:

       1     //class ReflectionRepaintManager extends RepaintManager
      2 private void installRepaintManager() {
      3 ReflectionRepaintManager manager = new ReflectionRepaintManager();
      4 RepaintManager.setCurrentManager(manager);
      5 }
      6
      7 class ReflectionRepaintManager extends RepaintManager
      8 {
      9 //該方法重載自RepaintManagr,當用戶代碼調(diào)用repaint之后,swing框架會將需要重繪的臟區(qū)域
      10 //傳遞給RepaintManager的addDirtyRegion方法,該方法中將會根據(jù)自己的需要自行擴展臟區(qū)域,
      11 //之后在通過調(diào)用父類RepaintManager缺省的addDirtyRegion方法,將更新后的重繪區(qū)域重新交給
      12 //swing的EDT去處理。
      13 public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
      14 Rectangle dirtyRegion = getDirtyRegion(c);
      15 int lastDeltaX = c.getX();
      16 int lastDeltaY = c.getY();
      17 Container parent = c.getParent();
      18 while (parent instanceof JComponent) {
      19 if (!parent.isVisible()) {
      20 return;
      21 }
      22 //如果父類是反射Panel,則將當前需要重繪的區(qū)域直接覆蓋到相應(yīng)的反射區(qū)域,以便是
      23 //相應(yīng)的反射區(qū)域也能和原本需要更新區(qū)域一同更新。
      24 if (parent instanceof ReflectionPanel) {
      25 x += lastDeltaX;
      26 y += lastDeltaY;
      27 int gap = contentPane.getHeight() - h - y;
      28 h += 2 * gap + h;
      29 lastDeltaX = lastDeltaY = 0;
      30 c = (JComponent)parent;
      31 }
      32 lastDeltaX += parent.getX();
      33 lastDeltaY += parent.getY();
      34 parent = parent.getParent();
      35 }
      36 super.addDirtyRegion(c, x, y, w, h);
      37 }
      38 }

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多