使用 FrameLayout 佈局,單點觸控來動態移動 TextVeiw 的範例

/*
使用 FrameLayout 佈局,單點觸控來動態移動 TextVeiw 的範例

方法一:
    tv = (TextView)findViewById(R.id.textView1);
    FrameLayout.LayoutParams lay_params = (FrameLayout.LayoutParams)tv.getLayoutParams();
    lay_params.setMargins(left, top, right, bottom);
    tv.setLayoutParams(params);
    
方法二:
    tv = (TextView)findViewById(R.id.textView1);
    tv.setPadding(left, top, right, bottom);
*/


package com.ccc.app03;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.*;
import android.widget.*;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
import android.view.ViewGroup.LayoutParams;


public class MainActivity extends Activity {

    private float t_X;
    private float t_Y;
    private TextView tv ;
   

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 取得 TextView 物件,id為textView1
        tv = (TextView)findViewById(R.id.textView1);

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }



    // 利用 MotionEvent 處理觸控程序
    public boolean onTouchEvent(MotionEvent event) {

        t_X = event.getX();       // 觸控點的 X 軸位置
        t_Y = event.getY() -50;   // 觸控點的 Y 軸位置,減50是為了更接近觸控點
         
          //getRawX,getRawY 相對於螢幕位置坐標;getX,getY 相對於容器上的位置坐標

          //設定物件變數lay_params並初始化
        FrameLayout.LayoutParams lay_params = (FrameLayout.LayoutParams)tv.getLayoutParams();

        // 判斷觸控的動作
        switch( event.getAction() ) {

            case MotionEvent.ACTION_DOWN:  // 按下
               
                    //動態設定textView1的位置
                lay_params.setMargins((int)t_X,(int)t_Y,0,0);
                    tv.setLayoutParams(params);
                   
                break;

            case MotionEvent.ACTION_MOVE:  // 拖曳移動

                //動態設定textView1的位置
                lay_params.setMargins((int)t_X,(int)t_Y,0,0);
                    tv.setLayoutParams(params);
                   
                break;

            case MotionEvent.ACTION_UP:  // 放開

                //動態設定textView1的位置
                lay_params.setMargins((int)t_X,(int)t_Y,0,0);
                    tv.setLayoutParams(params);
                   
                break;
                   
        } //Switch End
         
    }   //onTouchEvent() End


}

Toad--不要讓Schema Browser的Script產生Drop的指令

當我們利用Toad來自動產生Objects的Script時,都會加上Drop的DDL指令,
為了避免不小心複製到Drop的指令,可以將它關閉起來。

在「Schema Browser」中任選一個object,在Script頁籤中選擇下面的圖示:


取消「Drop statement」的勾選就可以了。

JAVA--以例子來看&、&&與 |、||的差異


public class test023  {
    public static void main(String[] args) {
      
       int a = 1, b = 2; 
       
      if (a > 1 & b++ >2){ System.out.println("Hello"); } 
      System.out.println("a = " + a + ", b = " + b); 

      a = 1 ;
       b = 2 ;
       
      if (a > 1 && b++ > 2){ System.out.println("Hello"); } 
       System.out.println("a = " + a + ", b = " + b); 
     
     }

上面的結果如下:

a=1,b=3
a=1,b=2

雖然最後的結果都是 false,兩個if都看不到Hello,但是 b 的值卻有不同的變化。
當 a > 1 = false,「&」會繼續執行 b++,所以最後 b = 3
當 a > 1 = false,「&&」不會執行 b++ ,所以最後 b = 2

雖然左方運算的結果是false,已符合「and」邏輯,最後一定是false,但是「&」還是會執行右方的運算;
而「&&」發現左方運算的結果已經是false,就不需要再執行右方的運算。

但是如果把if的邏輯改為 a = 1 ,因為左方運算的結果為true,所以右方的運算無論如何都要執行,
才能知道最後的布林值是true或是false,所以兩個if最後 b = 3 


「|」與「||」也是一樣的道理,測試如下:
public class test024  {
    public static void main(String[] args) {
      
       int a = 2, b = 2; 
       
      if (a > 1 | b++ >2){ System.out.println("Hello"); } 
      System.out.println("a = " + a + ", b = " + b); 

      a = 2 ;
       b = 2 ;
       
      if (a > 1 || b++ > 2){ System.out.println("Hello"); } 
       System.out.println("a = " + a + ", b = " + b); 
     
     }
}

因為左方的運算 a > 1 是true,對「or」邏輯而言,已經決定最後的結果是true,
但是「|」還是會執行右方的運算,所以 b = 3;而「||」的 b = 2

如果改為 a < 1,則右方運算必定會執行,才能決定最後的結果是true或false,所以兩個b都是3

Android Studio TextView.setText 中文亂碼

我用一個按鈕來改變TextView的內容,程式碼如下:
TextView t1 = (TextView)findViewById(R.id.txt1);
t1.setText("中文測試");

編譯後在模擬器中執行,結果卻是亂碼。

原因應該是出在中文編碼的問題,所以更改編輯器的右下方,將ISO-8859-1改為UTF-8
結果還是跑出亂碼,而且還發現中文字如果是單數,編譯時還會出現錯誤的訊息。
例如:t1.setText("中文測");


猜想應該是因為Android Studio的UTF-8並未將中文當成中文字,所以在編譯「"中文測"」時,
連帶把雙引號的位元組也納入中文字的位元組後再儲存字元,以致找不到最後的雙引號而錯誤。

猜想應該是因為Android Studio的UTF-8並未將中文當成中文字,所以在編譯「"中文測"」時,
連帶把雙引號的位元組也納入中文字的位元組後再儲存字元,以致找不到最後的雙引號而錯誤。


最後我是把它更改為Big5,重新Reload後,中文就變正常了




為了以後方便,連setting也一起更變:

Android模擬器執行app時出現Unfortunately XXXX has Stopped

我是用 Android Studio 來練習 APP程式,依照文件做了一個按鈕,可以改變TextView顯示的文字內容。
但是在模擬器執行時出現Unfortunately XXXX has Stopped,程式就自動關掉了。

可以從Android Studio 的 Log中找出問題的所在,如下圖:


找到的Log的記錄如下:
09-13 00:49:08.627      795-795/? E/AndroidRuntime: FATAL EXCEPTION: main
        java.lang.IllegalStateException: Could not find a method btn1_onClick(View)
       in the activity class com.example.apptest002.MainActivity for onClick handler 
       on view class android.widget.Button with id 'btn1'

上面指出找不到btn1_onClick這個method,原來是我在Button中設定onClieck的method是btn1_onClick,
但是在MainActivity.java卻誤寫method名稱為button1_onClick,更改後就成功了。

        

同類型的資料做分類群組排序時,可用函數dense_rank()、row_number()、rank()

有時候我們想要將同類型的資料做分類群組排序時,可用函數dense_rank()、row_number()、rank()

例如要抓取每個班級數學成績前10名的學生 ,student :學生資料 ;score_info :數學成績資料

--情況1(dense_rank()):如果有相同成績,則序列都一樣,如A、B同為100分,則序列都是1
SELECT student_id "學號" , student_name "學生姓名" , class_id "班級編號" ,
    FROM(
              SELECT s1.student_id , s1. student_name, s1.class_id ,
                          --先將班級(s1.class_id)分為不同群組,再依成績(s2.score)排序,並在每一個群組內給予1到N的序列
                          dense_rank() over(PARTITION BY s1 . class_id ORDER BY s2. score DESC ) rank_num
                  FROM student s1,score_info s2
                  WHERE s1.student_id = s2 . student_id)
    WHERE rank_num < 11;
  

--情況2( row_number()):不論是否有相同成績,則序列一直編下去,如A、B同為100分,則A為1、B為2
SELECT student_id "學號" , student_name "學生姓名" , class_id "班級編號" ,
    FROM(
              SELECT s1.student_id , s1. student_name, s1.class_id ,
                         -先將班級(s1.class_id)分為不同群組,再依成績(s2.score)排序,並在每一個群組內給予1到N的序列
                         row_number() over(PARTITION BY s1 . class_id ORDER BY s2. score DESC ) rank_num
                  FROM student s1,score_info s2
                  WHERE s1.student_id = s2 . student_id)
    WHERE rank_num < 11;
   
--情況3(rank()):序列一直因為同分數而跳號,如A、B同為100分,C為99分,則A為1、B為1、C為3
SELECT student_id "學號" , student_name "學生姓名" , class_id "班級編號" ,
    FROM(
              SELECT s1.student_id , s1. student_name, s1.class_id ,
                         -先將班級(s1.class_id)分為不同群組,再依成績(s2.score)排序,並在每一個群組內給予1到N的序列
                         rank() over(PARTITION BY s1 . class_id ORDER BY s2. score DESC ) rank_num
                  FROM student s1,score_info s2
                  WHERE s1.student_id = s2 . student_id)
    WHERE rank_num < 11;

JAVA使用JScrollPane、JTextArea注意事項,以免捲軸會失效

下面是一個自己蝀習的範例原始碼:

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class test015 {
  public static void main(String[] args) {
    JFrame f = new JFrame("Text Area Examples");
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     JTextArea content = new JTextArea(100,10) ;
     JScrollPane g = new JScrollPane(content);
     f.setBounds(100,100,300,300);

     f.setVisible(true);
     f.setLayout (null); //nul表示自訂樣式,不使用預設的樣式         
     //content.setBounds(10,10,100,100);
     g.setBounds(110,10,200,100);
     f.add(g);
  }
}

當宣告  JScrollPane g = new JScrollPane(content);  之後,物件g就會內嵌物件content並在畫面上顯示,
因此如果要宣告物件的在畫面上的大小,就應該要用JScrollPane的方法來設定,
也就是用JScrollPane的setBounds來設定,千萬不要用JTextArea的setBounds來設定,否則會導致捲軸無法使用。

java 使用jdbc連線sqlite

1、因為SQLite官方並沒有JDBC的Driver,所以先到 https://bitbucket.org/xerial/sqlite-jdbc下載

2、將下載的sqlite-jdbc-3.7.2.jar,放到Java的classpath內,並在classpath內加入jar
      如:set classpath=d:\java_test ; d:\java_test\sqlite-jdbc-3.7.2.jar

3、範例的程式碼如下:
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

//執行程式前,要先設定正確的CLASSPATH,
//如在Windows: set CLASSPATH=d:\java_test ; d:\java_test\sqlite-jdbc-3.7.2.jar

public class test020 {
  public static void main(String[] args) throws ClassNotFoundException {
    Class.forName("org.sqlite.JDBC"); // 建立database的連線
    Connection connection = null;
  
try{
      connection = DriverManager.getConnection("jdbc:sqlite:d:\\java_test\\sample.db"); //要加上跳脫字元「\」
      Statement statement = connection.createStatement();
      statement.setQueryTimeout(30);  //set timeout to 30 sec.
 statement.executeUpdate("drop table test01");
      statement.executeUpdate("create table test01 (id integer, name string)");
 statement.executeUpdate("insert into test01 values (1,'張三')");
 statement.executeUpdate("insert into test01 values (2,'李四')");
 
 ResultSet rs = statement.executeQuery("select * from test01");
      while(rs.next()) //逐筆讀取ResultSet的資料
      {
        System.out.println("姓名 = " + rs.getString("name"));
        System.out.println("編號 = " + rs.getInt("id"));
      }
 
    }
    catch (SQLException e) {
      System.err.println(e.getMessage());
    }
finally
    {
      try
      {
        if(connection != null)
          connection.close();
      }
      catch(SQLException e)
      {
        System.err.println(e); //connection close failed.
      }
    }
  }
  
}