-->

2017年01月

BroadcastReceiverクラスを継承したクラスを作って、onReceiveでACTION_HEADSET_PLUG、ACTION_AUDIO_BECOMING_NOISYを取ってやる。
ACTION_HEADSET_PLUGは、ヘッドホンが刺さったり抜けたりしたときに受信する。ACTION_AUDIO_BECOMING_NOISYはヘッドホンが抜けてスピーカーから大きな音がなるよってときに受信する。Bluetoothオーディオが切断されたときもACTION_AUDIO_BECOMING_NOISYを受信する。

public class MainActivity extends AppCompatActivity {
    /**
     * ヘッドセット状態取得レシーバクラス
     */
    private class HeadSetPlugReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if(action.equals(Intent.ACTION_HEADSET_PLUG)) {
                int state = intent.getIntExtra("state", -1);
                if(state == 0) { // ヘッドホンが抜けた
                    System.out.println("ヘッドホンが抜けた(ACTION_HEADSET_PLUG)");
                }
            } else if(action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
                System.out.println("ヘッドホンが抜けた(ACTION_AUDIO_BECOMING_NOISY)");
            }
        }
    }

    private HeadSetPlugReceiver headSetPlugReceiver;

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

        // ヘッドセット状態を監視
        headSetPlugReceiver = new HeadSetPlugReceiver();
        registerReceiver(headSetPlugReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
        registerReceiver(headSetPlugReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
    }
}

このエントリーをはてなブックマークに追加

スレッドを使ってみる。まず、ThreadクラスがUWPにはないのでこれは使えない。スレッドプールのTaskクラスを使うことになる。

        private void button_Click(object sender, RoutedEventArgs e)
        {
            Task task = new Task(async () =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Debug.WriteLine(i);
                    await Task.Delay(1000);
                }
                Debug.WriteLine("thread");
            });
            task.Start();
        }

Threadクラスが使えないのでSleepができない。かわりにTask.Delayを使う。

次に別のスレッドから直接UIの操作はできないんだが、それをするにはDispatcher.RunAsyncを使う。
こんな感じだ。

        private void button_Click(object sender, RoutedEventArgs e)
        {
            button.IsEnabled = false;
            Task task = new Task(async () =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Debug.WriteLine(i);
                    await Task.Delay(1000);
                }
                Debug.WriteLine("thread");
                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    button.IsEnabled = true;
                });
            });
            task.Start();
        }


このエントリーをはてなブックマークに追加

恒例になっているTwitterのタイムライン風の画面を作ってみるw

001

新規にプロジェクトを作成して、ストーリボードを開いてテーブルビューをはっ付けておく。
貼ったテーブルビューにTable View Cellをドラッグ&ドロップする。
貼ったテーブルビューセルのアトリビュート・インスペクターでIdentifierにcustomcellと入力する。

003

テーブルビューセルに部品を配置する。
ユーザーアイコンにあたるImageViewを貼って、制約を次のように設定する。Content ModeをAspect Fitにする。

004

Labelを貼って、制約を次のように設定する。フォントサイズを20にする。

005

TextViewを貼って、制約を次のように設定する。Scrolling Enabled、Editableのチェックを外す。

006

新規にCocoa Touch Classを作成してセルのクラスを作る。クラス名はArticleTableViewCell、SubclassはUITableViewCellにしておく。

007

ArticleTableViewCellクラスとストーリボードに貼ったTableViewCellと接続する。
customcellを選んでIdentity Inspectorを選んでClassでArticleTableViewCellを選ぶ。

008

いったんビルドする。

customcellに貼った部品をctlキーを押しながらドラッグ&ドロップしてArticleTableViewCellに繋ぐ。ArticleTableViewCellはこんな感じになる。

import UIKit

class ArticleTableViewCell: UITableViewCell {
    @IBOutlet weak var icon: UIImageView!
    @IBOutlet weak var user: UILabel!
    @IBOutlet weak var comment: UITextView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Assets.xcassetsにユーザーアイコン用のイメージをImageって名前で追加する。

表示するデータのクラスArticleを作る。

import UIKit

class Article: NSObject {
    var icon:UIImage
    var user:String
    var comment:String
    
    init(icon:UIImage, user:String, comment:String) {
        self.icon = icon
        self.user = user
        self.comment = comment
    }
}

ViewControllerクラスにUITableViewDataSourceプロトコルを実装し、ストーリボードのテーブルビューのdataSourceとViewControllerを接続する。ViewControllerクラスはこんな感じ。

import UIKit

class ViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
 
    // ダミーのデータを用意
    var list:[Article] = [
        Article(icon: UIImage(named:"Image")!, user: "user1", comment: "あいうえお"),
        Article(icon: UIImage(named:"Image")!, user: "user1", comment: "あいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえお")
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // セルの高さを自動的に決まるように設定する
        tableView.estimatedRowHeight = 20
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // データの数を返す
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count;
    }
    
    // セルにデータを設定して返す
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "customcell") as! ArticleTableViewCell
        let row = indexPath.row
        cell.icon.image = list[row].icon
        cell.user.text = list[row].user
        cell.comment.text = list[row].comment
        return cell;
    }
}


このエントリーをはてなブックマークに追加

JavaでExcelファイル(.xlsx)を読む:POIサンプル: 万象酔歩に詳しく書いてあるけど、ちょっと古いのでこの投稿を参考に最新版で試してみる。

POIをダウンロードページ(Apache POI - Download Release Artifacts)からバージョン3.15のバイナリ版をダウンロードする。
ダウンロードしたファイルを解凍して、poi-3.15.jar、poi-ooxml-3.15.jar、poi-ooxml-schemas-3.15.jar、ooxml-lib/xmlbeans-2.6.0.jar、lib/commons-collections4-4.1.jarを追加する。とりあえず、次に示すソースを動かすのに必要なライブラリはこんだけだ。実際はダウンロードしたファイルに含まれているjarファイルを全部追加した方がいいだろな。

試したソースはこんな感じだ。

package testexcel;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 *
 * @author miyamoto
 */
public class TestExcel {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Workbook workbook;
        
        // ファイルオープン
        try (InputStream is = TestExcel.class.getResourceAsStream("test.xlsx")) {
            workbook = new XSSFWorkbook(is);
            
            for (Sheet sheet : workbook) {  // 全シートまわす
                System.out.println("Sheet:" + sheet.getSheetName());
                for (Row row : sheet) {     //  行でまわす
                    for (Cell cell : row) { // 行内のセルでまわす
                        System.out.print(getStr(cell) + " ");
                    }
                    System.out.println();
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(TestExcel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    // セルのデータを文字列で取得
    public static String getStr(Cell cell) {
        switch(cell.getCellTypeEnum()) {
            case BOOLEAN:
                return Boolean.toString(cell.getBooleanCellValue());
            case FORMULA:
//                return cell.getCellFormula();     // ← 計算式が返る
                return Double.toString(cell.getNumericCellValue()); // 計算結果が返る。
                                                                    // 0除算でエラーになる場合例外が発生する。
            case NUMERIC:
                return Double.toString(cell.getNumericCellValue());
            case STRING:
                return cell.getStringCellValue();
            default:
                return "";
        }
    }
}

セルのタイプを取得するメソッドのgetCellTypeが非推奨だったのでドキュメントによると「getCellTypeEnumを使え」みたいに書いてあったのだが、これも非推奨っぽい(^^;)代わりを探してみたんだが、それっぽいのがないのでしかたがないのでこれを使っている。

(追記)
SEさんがコメントされていますが、getCellTypeEnumが非推奨になっているのはpoiのバグらしいです。3.16で直っているそうです。


このエントリーをはてなブックマークに追加

Twitterのタイムラインみたいなリストを作ってみる。バインディングのあたりはは、[UWP] Hello World的なものに詳しく書いてあるのでこちらも参考にしてくれ。

001

・空白のUWPを新規作成する
・プロジェクトにImagesフォルダを作ってアカウントのアイコンの代わりになるimage.pngを追加する。
・データのクラスを作る。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Media.Imaging;

namespace TestCustomList2
{
    class Article
    {
        public String User { get; set; }
        public String Comment { get; set; }
        public BitmapImage Image { get; set; }

        public Article(BitmapImage image, String user, String comment)
        {
            User = user;
            Comment = comment;
            Image = image;
        }
    }
}

・MVVMのViewModelにあたるクラス(MainPageViewModel)を作る。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Media.Imaging;

namespace TestCustomList2
{
    class MainPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public MainPageViewModel()
        {
            list = new ObservableCollection<Article>();

            BitmapImage img = new BitmapImage(new Uri("ms-appx:///Images/image.png"));
            list.Add(new Article(img, "user1", "あいうえお"));
            list.Add(new Article(img, "user1", "あいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえお"));
        }

        private void NotifyPropertyChanged([CallerMemberName]string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public ObservableCollection<Article> list { get; set; }
    }
}

・画面をデザインする。MainView.xamlを開いてListViewを貼る。
・貼ったListViewを右クリックして、追加テンプレートの編集 - 生成されたアイテムの編集(ItemTemplate) - 空アイテムの作成を選ぶ。

002

・定義先でlistViewを選ぶ。

004

・DataTemplateのGridを2×2にする。
・グリッドの0カラムの0〜1行にImageを追加してとりあえずSourceプロパティでImages/image.pngを選ぶ。ImageのWidthを64にする。Marginを10にする。
・Gridの0カラムのWidthをAuto、0、1ローのHeightをAutoにする。
・ユーザー名を表示するTextBlockを1カラム0ローに追加する。Marginを10にする。フォントサイズを20px、太字にする。
・コメントを表示するTextBlockを1カラム1ローに追加する。Marginを10にする。

005

・一度ビルドしておく。
・View Modelと接続していく。デザイナーでPageを選択して、メニューから書式 - デザイン時のDataContextの設定を選ぶ。表示されるダイアログでDataContextの種類でDesignInstance、TypeでMainPageViewModelを選ぶ。IsDesignTimeCreatableをチェックする。
・ListViewのItemsSourceのデータバインディング作成でlistプロパティと接続する。
・デザイナーで貼り付けているListViewで右クリックして、追加テンプレートの編集 - 生成されたアイテムの編集 - 現在の編集を選ぶ。

006

・貼ってあるImageのSourceをImageと接続する。
・貼ってあるユーザー名のTextBlockのTextをUserと接続する。
・貼ってあるコメントのTextBlockのTextをCommentと接続する。
・MainPageクラスでMainPageViewModelのインスタンスを作成してDataContextに設定する。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// 空白ページのアイテム テンプレートについては、http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 を参照してください

namespace TestCustomList2
{
    /// <summary>
    /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private MainPageViewModel viewModel = new MainPageViewModel();

        public MainPage()
        {
            this.InitializeComponent();

            DataContext = viewModel;
        }
    }
}


このエントリーをはてなブックマークに追加

↑このページのトップヘ