雖然網路上文章滿多的,但還是紀錄一下以免忘記。
會有這個問題產生主要是在Android 4.0版本以上才會出現,確切原因不清楚,但應該是增加安全
性理由所以才修改成這樣的(?)
這問題就是如同字面上意思:
你在主線程上面呼叫Network類相關API
這時候該如何解決呢??
1)使用分流法(開個新的Thread)來操作網路,但如果我就是要調整並顯示UI介面呢?
2)在setContentView(R.layout.activity_main)下面新增
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
即可解決該問題
2014年8月11日 星期一
[Android/Java] Thread(執行緒)的使用+UDP Send / Receive+Socket
在使用Thread的時候,必須要先知道執行緒(Thread)是甚麼?
否則只是看看範例,卻只得其一不得其二。
執行緒是一種可以在程式背景執行的一個Process(程序),同時可以有多個執行緒一起執行。
由於可以多線程,因此大大增加可用性。
Thread的結構大概就是
public class ChatServer extends Thread{
private DatagramSocket server = null;
private static final int PORT = 4000;
//宣告變數
public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
//建構子
public void run(){
byte[] byte100 = new byte[100];
DatagramPacket dPacket = new DatagramPacket(byte100, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
Log.d("User","While 1");
while(true)
{
//印出來到螢幕上
Log.d("User","While 2");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
//主要在跑的地方(主程式)
在呼叫Thread的時候,以上面範例為例,我們呼叫時使用:
chatserver = new ChatServer();
new這個class,他會跑進建構子裡面,但還不會進去run()函式
chatserver.start();
執行run()這個函式,由於run裡面有while()迴圈,所以會一直跑不停
(在這兩行外面要夾try catch否則會有error)
-----------------------------------------------------------------------------------------------------------
上面解釋完Thread了,下面要講的是如何在Android上面使用執行緒的概念做UDP的發送與接收,
但這目前有個問題就是模擬器(emulator)與電腦的連線還沒有試做成功,在Emulator-Emulator是可
以成功傳送-接收的。
傳送部分:
目標:寫一個Thread,讓他不停傳送給指定IP+指定Port
內容:
public class ChatSender extends Thread{
public void run(){
DatagramSocket socket = null;
try
{
socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
Log.d("IP Address", serverAddress.toString());
String str = "Test Thread sender";
//創建一個用於發送的DatagramPacket對象
DatagramPacket packet=new DatagramPacket(str.getBytes(),str.length(),serverAddress,4000);
//發送數據
while(true)
{
socket.send(packet);
Thread.sleep(1000);
}
}
catch(SocketException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(UnknownHostException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(IOException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(Exception e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
finally{
if(socket != null){
socket.close();
}
}
}
}
否則只是看看範例,卻只得其一不得其二。
執行緒是一種可以在程式背景執行的一個Process(程序),同時可以有多個執行緒一起執行。
由於可以多線程,因此大大增加可用性。
Thread的結構大概就是
public class ChatServer extends Thread{
private DatagramSocket server = null;
private static final int PORT = 4000;
//宣告變數
public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
//建構子
public void run(){
byte[] byte100 = new byte[100];
DatagramPacket dPacket = new DatagramPacket(byte100, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
Log.d("User","While 1");
while(true)
{
//印出來到螢幕上
Log.d("User","While 2");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
//主要在跑的地方(主程式)
在呼叫Thread的時候,以上面範例為例,我們呼叫時使用:
chatserver = new ChatServer();
new這個class,他會跑進建構子裡面,但還不會進去run()函式
chatserver.start();
執行run()這個函式,由於run裡面有while()迴圈,所以會一直跑不停
(在這兩行外面要夾try catch否則會有error)
-----------------------------------------------------------------------------------------------------------
上面解釋完Thread了,下面要講的是如何在Android上面使用執行緒的概念做UDP的發送與接收,
但這目前有個問題就是模擬器(emulator)與電腦的連線還沒有試做成功,在Emulator-Emulator是可
以成功傳送-接收的。
傳送部分:
目標:寫一個Thread,讓他不停傳送給指定IP+指定Port
內容:
public class ChatSender extends Thread{
public void run(){
DatagramSocket socket = null;
try
{
socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
Log.d("IP Address", serverAddress.toString());
String str = "Test Thread sender";
//創建一個用於發送的DatagramPacket對象
DatagramPacket packet=new DatagramPacket(str.getBytes(),str.length(),serverAddress,4000);
//發送數據
while(true)
{
socket.send(packet);
Thread.sleep(1000);
}
}
catch(SocketException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(UnknownHostException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(IOException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(Exception e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
finally{
if(socket != null){
socket.close();
}
}
}
}
大概可以看到DatagramSocket+DatagramPacket這兩個API,
DatagramSocket我的理解是用於Socket連線,而DatagramPacket則是負責傳送的封包內容。
*DatagramPacket(封包的byte[]陣列,封包的長度,IP位址,Port);
至於InetAddress的部分是為了要確定本機IP是多少。
接收部分:
目標:寫一個Thread,讓他不停到指定的Port接收封包,直到有接收到才印出來,之後繼續hold住等待封包傳送過來。
內容:
public class ChatServer extends Thread{
private DatagramSocket server = null;
private static final int PORT = 4000;
public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
public void run(){
byte[] byte100 = new byte[100];
DatagramPacket dPacket = new DatagramPacket(byte100, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
Log.d("User","While 1");
while(true)
{
//印出來到螢幕上
Log.d("User","While 2");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
private void CloseSocket(DatagramSocket socket) throws IOException{
socket.close();
}
}
目標:寫一個Thread,讓他不停到指定的Port接收封包,直到有接收到才印出來,之後繼續hold住等待封包傳送過來。
內容:
public class ChatServer extends Thread{
private DatagramSocket server = null;
private static final int PORT = 4000;
public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
public void run(){
byte[] byte100 = new byte[100];
DatagramPacket dPacket = new DatagramPacket(byte100, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
Log.d("User","While 1");
while(true)
{
//印出來到螢幕上
Log.d("User","While 2");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
private void CloseSocket(DatagramSocket socket) throws IOException{
socket.close();
}
}
UDP接收的部分同樣也需要DatagramSocket/DatagramPacket,不過剛剛是Send 現在則是receive
為了存放接收的資料,前面會先new一個byte[]陣列用以存放資料。
在server.receive(dPacket);這邊如果沒有資料進來的話,他不會往下跑,會一直等待在這邊,直到接
收到資料才會執行下一行。這是必須特別注意的!
MainActivity的部分:
public class MainActivity extends ActionBarActivity {
private Handler exHandler;
private TextView txv;
private ChatServer chatserver;
private ChatSender chatsender;
public static InetAddress IP;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txv = (TextView) findViewById(R.id.textView);
try{
//IP = InetAddress.getLocalHost();
chatserver = new ChatServer();
chatserver.start();
chatsender = new ChatSender();
chatsender.start();
Log.d("User","Thread start...");
}catch(Exception e)
{
String str = e.toString();
Log.e("Error by User", str);
}
}
protected void onPause(){
super.onPause();
if(chatserver != null)
{
if(!chatserver.isInterrupted())
{
chatserver.interrupt();
}
}
}
}
然後要記得AndroidManifest.xml這邊要增加INTERNET的Uses-Permission
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.thread_example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.thread_example.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
結論: UDP 傳送及接收其實不容易,看似簡單但很多細節如果沒有注意到就會失敗!
2014年7月15日 星期二
[Android] Eclipse好用快捷鍵
在使用Eclipse時候常常很苦惱,因為不是很好用(沒背快捷鍵)
這邊記錄一下,好用的
1.Ctrl +D = 整行刪除
2.圈起來 + Ctrl+Shift+f = 該區域自動排版
3.圈起來 + Ctrl+/ = 該區域註解掉
4.Ctrl+Shift+O = 自動import所需的類別
大概就這些,背起來會很有用喔!
這邊記錄一下,好用的
1.Ctrl +D = 整行刪除
2.圈起來 + Ctrl+Shift+f = 該區域自動排版
3.圈起來 + Ctrl+/ = 該區域註解掉
4.Ctrl+Shift+O = 自動import所需的類別
大概就這些,背起來會很有用喔!
2014年7月10日 星期四
[Android] UDP Socket Emulator to PC Sender / UDP Socket 使用Android 模擬器傳送給PC端 實作
歷經千辛萬苦,終於把這個東西給搞定了....一部分(接收的部分還不確定)
package com.example.sendudp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity implements OnClickListener {
Button Sender;
TextView err;
TextView check_send_data;
EditText input_str;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Sender = (Button) findViewById(R.id.sender);
err = (TextView) findViewById(R.id.error_txv);
check_send_data = (TextView) findViewById(R.id.send_txv);
input_str = (EditText) findViewById(R.id.edt);
Sender.setOnClickListener(this);
}
@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;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
DatagramSocket socket = null;
try
{
socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("10.192.172.130");
String str = input_str.getText().toString();
//創建一個用於發送的DatagramPacket對象
DatagramPacket packet=new DatagramPacket(str.getBytes(),str.length(),serverAddress,4000);
//發送數據
//socket.connect(serverAddress, 6000);
socket.send(packet);
check_send_data.setText(str);//顯示傳送的文字
}
catch(SocketException e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
catch(UnknownHostException e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
catch(IOException e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
catch(Exception e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
finally{
if(socket != null){
socket.close();
}
}
}
}
首先進去命令提示字元(按開始->輸入cmd)
輸入"telnet localhost 5554"(這邊要特別注意因為android emulator是5554所以才用telnet登入5554)
進入畫面如上,記得模擬器要開起來,否則Telnet會無法連線!
接著我們要重新定址(增加Port)
輸入指令redir add udp:5000:4000(這兩個數字可以任意變換, Local端:Guest端)
測試程式,隨意輸入文字,可以看到另一邊有收到(但是是ASCII碼)
如此就完成初步了,當然!!!!最重要的是程式碼,否則即使開啟了模擬器的port也無法傳送。
package com.example.sendudp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity implements OnClickListener {
Button Sender;
TextView err;
TextView check_send_data;
EditText input_str;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Sender = (Button) findViewById(R.id.sender);
err = (TextView) findViewById(R.id.error_txv);
check_send_data = (TextView) findViewById(R.id.send_txv);
input_str = (EditText) findViewById(R.id.edt);
Sender.setOnClickListener(this);
}
@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;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
DatagramSocket socket = null;
try
{
socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("10.192.172.130");
String str = input_str.getText().toString();
//創建一個用於發送的DatagramPacket對象
DatagramPacket packet=new DatagramPacket(str.getBytes(),str.length(),serverAddress,4000);
//發送數據
//socket.connect(serverAddress, 6000);
socket.send(packet);
check_send_data.setText(str);//顯示傳送的文字
}
catch(SocketException e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
catch(UnknownHostException e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
catch(IOException e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
catch(Exception e)
{
e.printStackTrace();
String error = e.toString();
err.setText(error);
}
finally{
if(socket != null){
socket.close();
}
}
}
}
然後一定會有人發現,即使如此還是沒法傳送,會出現Permission denied的exception
因此我們需要在bin/res/AndroidManifest.xml這邊修改,修改如下
記得要存檔,才會改變設定。
把權限開了,程式碼也沒有問題,Port也有設定好,大致上Android UDP Socket就算完成了。
不過因為我還沒寫接收的部分,所以接收的部分要在等寫完才能有教學
2014年6月25日 星期三
[C#/winform] MSChart使用實測+功能介紹
關於這個Microsoft Chart Control,網路上真的資料不多(不然就是簡體居多),有鑒於此,
這邊研究了很久以後...終於了解了一個大概,這邊寫一下心得跟使用說明。
可以看到Series就代表一條線(或是一組線,或數據),你可以透過Series調整他的各項功能
ChartArea: 這線所畫的區域
ChartType: 要怎樣的圖形表示呢? 折線/直條/橫條...等
像我這這邊加入了4個Series,因為我要做四條線(但下面範例我只有設定2條而已)
這邊可以看到Legends代表上面那個線條註釋,而底下如果太多數據要顯示(內建會變成一個顯示一個不顯示)就要用程式碼修改為不重疊(交叉顯示)。
以下範例是參考 SUEHILARY的學習手記 修改而成的:
------------------------------------------------------------------------------------------------------------
DateTime a = DateTime.Now;
DateTime b = DateTime.Now;
List<String> xValue = new List<string>();
xValue.Add(a.ToString());
xValue.Add(b.ToString());
string[] titleArr = { "活動1", "活動2" };
double[] yValues = { 269.23, 94 };
double[] yValues2 = { 120.14, 116 };
Chart1.Legends.Add("Legends1"); //圖例集合
//設定 Chart
Title title = new Title();
title.Text = "統計圖";
title.Alignment = ContentAlignment.MiddleCenter;
title.Font = new System.Drawing.Font("Trebuchet MS", 14F, FontStyle.Bold);
Chart1.Titles.Add(title);
//設定 ChartArea----------------------------------------------------------------------
//-----------------------------設定3D------------------------------//
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = true; //3D效果
Chart1.ChartAreas["ChartArea1"].Area3DStyle.IsClustered = true; //並排顯示
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Rotation = 40; //垂直角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Inclination = 50; //水平角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.PointDepth = 10; //數據條厚度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.WallWidth = 0; //外牆寬度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.LightStyle = LightStyle.Realistic; //光源
//-----------------------------設定3D------------------------------//
Chart1.ChartAreas["ChartArea1"].BackColor = Color.FromArgb(240, 240, 240); //背景色
Chart1.ChartAreas["ChartArea1"].AxisX.Enabled = AxisEnabled.True;
Chart1.ChartAreas["ChartArea1"].AxisX2.Enabled = AxisEnabled.False; //隱藏 X2 標示
Chart1.ChartAreas["ChartArea1"].AxisY2.Enabled = AxisEnabled.False; //隱藏 Y2 標示
Chart1.ChartAreas["ChartArea1"].AxisY2.MajorGrid.Enabled = false; //隱藏 Y2 軸線
Chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.LineColor = Color.FromArgb(150, 150, 150);//X 軸線顏色
Chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.LineColor = Color.FromArgb(150, 150, 150);//Y 軸線顏色
Chart1.ChartAreas["ChartArea1"].AxisY.LabelStyle.Format = "#.###";//設定小數點
//設定 Legends------------------------------------------------------------------------
Chart1.Legends["Legends1"].DockedToChartArea = "ChartArea1"; //顯示在圖表內
//Chart1.Legends["Legends1"].Docking = Docking.Bottom; //自訂顯示位置
Chart1.Legends["Legends1"].BackColor = Color.FromArgb(235, 235, 235); //背景色
//斜線背景
Chart1.Legends["Legends1"].BackHatchStyle = ChartHatchStyle.DarkDownwardDiagonal;
Chart1.Legends["Legends1"].BorderWidth = 1;
Chart1.Legends["Legends1"].BorderColor = Color.FromArgb(200, 200, 200);
//設定 Series-----------------------------------------------------------------------
//Chart1.Series["Series1"].ChartType = SeriesChartType.Line; //直條圖(Column),折線圖(Line),橫條圖(Bar)
//Chart1.Series["Series2"].ChartType = SeriesChartType.Line; //直條圖(Column),折線圖(Line),橫條圖(Bar)
//Chart1.Series["Series1"].ChartType = SeriesChartType.Bar; //橫條圖
Chart1.Series["Series1"].Points.DataBindXY(xValue, yValues);//Series1的XY數值放入圖中
Chart1.Series["Series1"].Legend = "Legends1";
Chart1.Series["Series1"].LegendText = titleArr[0];
Chart1.Series["Series1"].LabelFormat = "#.###"; //小數點
Chart1.Series["Series1"].MarkerSize = 8; //Label 範圍大小
Chart1.Series["Series1"].LabelForeColor = Color.FromArgb(0, 90, 255); //字體顏色
//字體設定
Chart1.Series["Series1"].Font = new System.Drawing.Font("Trebuchet MS", 10, System.Drawing.FontStyle.Bold);
//Label 背景色
Chart1.Series["Series1"].LabelBackColor = Color.FromArgb(150, 255, 255, 255);
Chart1.Series["Series1"].Color = Color.FromArgb(240, 65, 140, 240); //背景色
Chart1.Series["Series1"].IsValueShownAsLabel = true; // Show data points labels
Chart1.Series["Series2"].Points.DataBindXY(xValue, yValues2);
Chart1.Series["Series2"].Legend = "Legends1";
Chart1.Series["Series2"].LegendText = titleArr[1];
Chart1.Series["Series2"].LabelFormat = "#.###"; //小數點
Chart1.Series["Series2"].MarkerSize = 8; //Label 範圍大小
Chart1.Series["Series2"].LabelForeColor = Color.FromArgb(255, 103, 0);
Chart1.Series["Series2"].Font = new System.Drawing.Font("Trebuchet MS", 10, FontStyle.Bold);
Chart1.Series["Series2"].LabelBackColor = Color.FromArgb(150, 255, 255, 255);
Chart1.Series["Series2"].Color = Color.FromArgb(240, 252, 180, 65); //背景色
Chart1.Series["Series2"].IsValueShownAsLabel = true; //顯示數據
Chart1.Series["Series3"].Color = Color.FromArgb(22, 24, 18, 65); //背景色
Chart1.ChartAreas[0].AxisX.Interval = 1; //設置X軸坐標的間隔為1
Chart1.ChartAreas[0].AxisX.IntervalOffset = 1; //設置X軸坐標偏移為1
Chart1.ChartAreas[0].AxisX.LabelStyle.IsStaggered = true; //設置是否交錯顯示,比如數據多的時間分成兩行來顯示
------------------------------------------------------------------------------------------------------------
原本應該是要先宣告
Chart Chart1 = new Chart();
但我們已經拉了一個元件叫Chart1因此就不用再new(再new就會重複,造成錯誤)
而Series1,2也是因為在winform當中有設定過因此無須重複設定(一樣造成錯誤)
3D的部分,因人而異,但個人是建議
Chart1.ChartAreas["ChartArea1"].Area3DStyle.IsClustered = true; //並排顯示
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Rotation = 40; //垂直角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Inclination = 50; //水平角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.PointDepth = 10; //數據條厚度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.WallWidth = 0; //外牆寬度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.LightStyle = LightStyle.Realistic; //光源
這樣的設定比較好看,當然也可以改為不要並排顯示,一切取決於你的程式/數據多寡
背景色的部分應該無須多講解吧?
線條顏色修改的部分在Chart1.Series["Series"].Color = Color.FromArgb(自行設定色彩);
然後要修改Legend的文字則是在Chart1.Series["Series"].LegendText = "要顯示的文字";
目前遇到的問題跟解法都寫在這邊了,剩下的部分就等寫完再補一篇新的。
End
這邊研究了很久以後...終於了解了一個大概,這邊寫一下心得跟使用說明。
可以看到Series就代表一條線(或是一組線,或數據),你可以透過Series調整他的各項功能
ChartArea: 這線所畫的區域
ChartType: 要怎樣的圖形表示呢? 折線/直條/橫條...等
像我這這邊加入了4個Series,因為我要做四條線(但下面範例我只有設定2條而已)
這邊可以看到Legends代表上面那個線條註釋,而底下如果太多數據要顯示(內建會變成一個顯示一個不顯示)就要用程式碼修改為不重疊(交叉顯示)。
以下範例是參考 SUEHILARY的學習手記 修改而成的:
------------------------------------------------------------------------------------------------------------
DateTime a = DateTime.Now;
DateTime b = DateTime.Now;
List<String> xValue = new List<string>();
xValue.Add(a.ToString());
xValue.Add(b.ToString());
string[] titleArr = { "活動1", "活動2" };
double[] yValues = { 269.23, 94 };
double[] yValues2 = { 120.14, 116 };
Chart1.Legends.Add("Legends1"); //圖例集合
//設定 Chart
Title title = new Title();
title.Text = "統計圖";
title.Alignment = ContentAlignment.MiddleCenter;
title.Font = new System.Drawing.Font("Trebuchet MS", 14F, FontStyle.Bold);
Chart1.Titles.Add(title);
//設定 ChartArea----------------------------------------------------------------------
//-----------------------------設定3D------------------------------//
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = true; //3D效果
Chart1.ChartAreas["ChartArea1"].Area3DStyle.IsClustered = true; //並排顯示
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Rotation = 40; //垂直角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Inclination = 50; //水平角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.PointDepth = 10; //數據條厚度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.WallWidth = 0; //外牆寬度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.LightStyle = LightStyle.Realistic; //光源
//-----------------------------設定3D------------------------------//
Chart1.ChartAreas["ChartArea1"].BackColor = Color.FromArgb(240, 240, 240); //背景色
Chart1.ChartAreas["ChartArea1"].AxisX.Enabled = AxisEnabled.True;
Chart1.ChartAreas["ChartArea1"].AxisX2.Enabled = AxisEnabled.False; //隱藏 X2 標示
Chart1.ChartAreas["ChartArea1"].AxisY2.Enabled = AxisEnabled.False; //隱藏 Y2 標示
Chart1.ChartAreas["ChartArea1"].AxisY2.MajorGrid.Enabled = false; //隱藏 Y2 軸線
Chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.LineColor = Color.FromArgb(150, 150, 150);//X 軸線顏色
Chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.LineColor = Color.FromArgb(150, 150, 150);//Y 軸線顏色
Chart1.ChartAreas["ChartArea1"].AxisY.LabelStyle.Format = "#.###";//設定小數點
//設定 Legends------------------------------------------------------------------------
Chart1.Legends["Legends1"].DockedToChartArea = "ChartArea1"; //顯示在圖表內
//Chart1.Legends["Legends1"].Docking = Docking.Bottom; //自訂顯示位置
Chart1.Legends["Legends1"].BackColor = Color.FromArgb(235, 235, 235); //背景色
//斜線背景
Chart1.Legends["Legends1"].BackHatchStyle = ChartHatchStyle.DarkDownwardDiagonal;
Chart1.Legends["Legends1"].BorderWidth = 1;
Chart1.Legends["Legends1"].BorderColor = Color.FromArgb(200, 200, 200);
//設定 Series-----------------------------------------------------------------------
//Chart1.Series["Series1"].ChartType = SeriesChartType.Line; //直條圖(Column),折線圖(Line),橫條圖(Bar)
//Chart1.Series["Series2"].ChartType = SeriesChartType.Line; //直條圖(Column),折線圖(Line),橫條圖(Bar)
//Chart1.Series["Series1"].ChartType = SeriesChartType.Bar; //橫條圖
Chart1.Series["Series1"].Points.DataBindXY(xValue, yValues);//Series1的XY數值放入圖中
Chart1.Series["Series1"].Legend = "Legends1";
Chart1.Series["Series1"].LegendText = titleArr[0];
Chart1.Series["Series1"].LabelFormat = "#.###"; //小數點
Chart1.Series["Series1"].MarkerSize = 8; //Label 範圍大小
Chart1.Series["Series1"].LabelForeColor = Color.FromArgb(0, 90, 255); //字體顏色
//字體設定
Chart1.Series["Series1"].Font = new System.Drawing.Font("Trebuchet MS", 10, System.Drawing.FontStyle.Bold);
//Label 背景色
Chart1.Series["Series1"].LabelBackColor = Color.FromArgb(150, 255, 255, 255);
Chart1.Series["Series1"].Color = Color.FromArgb(240, 65, 140, 240); //背景色
Chart1.Series["Series1"].IsValueShownAsLabel = true; // Show data points labels
Chart1.Series["Series2"].Points.DataBindXY(xValue, yValues2);
Chart1.Series["Series2"].Legend = "Legends1";
Chart1.Series["Series2"].LegendText = titleArr[1];
Chart1.Series["Series2"].LabelFormat = "#.###"; //小數點
Chart1.Series["Series2"].MarkerSize = 8; //Label 範圍大小
Chart1.Series["Series2"].LabelForeColor = Color.FromArgb(255, 103, 0);
Chart1.Series["Series2"].Font = new System.Drawing.Font("Trebuchet MS", 10, FontStyle.Bold);
Chart1.Series["Series2"].LabelBackColor = Color.FromArgb(150, 255, 255, 255);
Chart1.Series["Series2"].Color = Color.FromArgb(240, 252, 180, 65); //背景色
Chart1.Series["Series2"].IsValueShownAsLabel = true; //顯示數據
Chart1.Series["Series3"].Color = Color.FromArgb(22, 24, 18, 65); //背景色
Chart1.ChartAreas[0].AxisX.Interval = 1; //設置X軸坐標的間隔為1
Chart1.ChartAreas[0].AxisX.IntervalOffset = 1; //設置X軸坐標偏移為1
Chart1.ChartAreas[0].AxisX.LabelStyle.IsStaggered = true; //設置是否交錯顯示,比如數據多的時間分成兩行來顯示
------------------------------------------------------------------------------------------------------------
原本應該是要先宣告
Chart Chart1 = new Chart();
但我們已經拉了一個元件叫Chart1因此就不用再new(再new就會重複,造成錯誤)
而Series1,2也是因為在winform當中有設定過因此無須重複設定(一樣造成錯誤)
3D的部分,因人而異,但個人是建議
Chart1.ChartAreas["ChartArea1"].Area3DStyle.IsClustered = true; //並排顯示
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Rotation = 40; //垂直角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Inclination = 50; //水平角度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.PointDepth = 10; //數據條厚度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.WallWidth = 0; //外牆寬度
Chart1.ChartAreas["ChartArea1"].Area3DStyle.LightStyle = LightStyle.Realistic; //光源
這樣的設定比較好看,當然也可以改為不要並排顯示,一切取決於你的程式/數據多寡
背景色的部分應該無須多講解吧?
線條顏色修改的部分在Chart1.Series["Series"].Color = Color.FromArgb(自行設定色彩);
然後要修改Legend的文字則是在Chart1.Series["Series"].LegendText = "要顯示的文字";
目前遇到的問題跟解法都寫在這邊了,剩下的部分就等寫完再補一篇新的。
End
訂閱:
文章 (Atom)






