Страницы

Поиск по вопросам

вторник, 24 декабря 2019 г.

Библиотека для парсинга pdf в текст (android)

#java #android


Подскажите какую библиотеку можно использовать в Android Studio для парсинга pdf в текст?
    


Ответы

Ответ 1



https://stackoverflow.com/a/6118652/873481 Я использовал itext .jar - хорошая библиотека. Насчет Android Studio - не знаю, думаю, как и в обычном джава-проекте, можно просто присоединить .jar к проекту...

Jade запись объекта

#gulp #jade


Мое знание Jade - базовое, поэтому поэтому вопрос от новичка )))

Как можно(если можно) создать объект (не получая его из JSON или других внешних файлов)
в самом jade файле

Моя попытка - при которой получаю ошибку unexpexted text {

-var profiles = [
    {
        'name': 'anna',
        'age': 26
    }
]

Причину понимаю, это из-за перевода строки. Все работает если записать это в одну
строку, но при большем объеме это не удобно.

-var profiles = [{'name':'anna','age': 26}]

Может кто сталкивался с подобным и знает методы, как правильно это записывается (если
такое вообще возможно), если нет буду грузить из внешки.
    


Ответы

Ответ 1



Попробуйте так - var profiles = { 'name': 'anna', 'age': 26 };

Ответ 2



В Jade блоки небуфиризированного JavaScript-кода обрамляются при помощи символа - и идущих за ним строк с отступом: - var profiles = [ { 'name': 'anna', 'age': 26 } ] // код сверху и снизу от этой строки // принадлежит одному блоку var foo = 'bar'; foo += ' of gold'; p А здесь уже идут strong обычные | конструкции Jade Блок кода заканчивается последней строкой c отступом.

Условный оператор if на Clojure

#lisp #clojure


Здравствуйте! Ещё в самом начале изучения Clojure. Подскажите пожалуйста.

У меня есть clojure-проект. Я использую шаблонизатор hiccup и стили Bootstrap. Всё
работает. Но вот только не понимаю как работают условные операторы в моём случае.

Вот мой код:

Файл project.clj:

(defproject yupppie "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "ссылка (ссылка словом потому что не позволяет репутация вставлять)"
  :license {:name "Eclipse Public License"
            :url "ссылка"}
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [ring "1.4.0"]
                 [compojure "1.4.0"]
                 [hiccup "1.0.5"]]
  :plugins [[lein-ring "0.9.7"]]
  :ring {:handler yupppie.core/app})


Файл yupppie.core:

(ns yupppie.core
  (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.params :refer [wrap-params]]
            [clojure.pprint :refer :all]
            [hiccup.core :refer :all]
            [hiccup.page :refer [include-css include-js]]))

(defn home []
  (html
    [:head (include-css "/bootstrap-3.3.6-dist/css/bootstrap.min.css")
     (include-css "/styles.css")
     (include-css "https://fonts.googleapis.com/icon?family=Material+Icons")
     (include-js "/bootstrap-3.3.6-dist/js/bootstrap.min.js")]

[:body
      [:div {:class "col-lg-6"}
      [:div {:class "input-group"}
      [:input {:type "text" :class "form-control" :placeholder "How old are you?"}
      [:span {:class "input-group-btn"}
      [:button {:class "btn btn-default" :type=" button"} "Go, baby!"]]]]]]))

                                            ;
(defroutes app
           (route/resources "/")
           (GET "/" [] (home))
           (POST "/saveform" req
                 (with-out-str (clojure.pprint/pprint (:params req)))))
(def apps
  (wrap-params app))


Я стал изучать его недавно, так что пока не очень понимаю.

У меня есть простая форма. И при вводе в поле цифры меньше 18 и нажатии на кнопку,
нужно сделать так чтобы показывалась одна картинка, а при вводе цифры 18 или больше
другая картинка. Вот как мне использовать условный оператор if, чтобы это заработало?
Куда вставлять код и что писать? 
    


Ответы

Ответ 1



Рассчитываю, что вы разберётесь, как прислать значение в форме. Я предположу, что с этим вы разобрались и в параметрах к запросу прилетает нужное значение. Предположу, что строка с присланным числом доступна в параметрах под ключом age и потому может быть забиндена в Compojure, как: (POST "/" [age] ???) Там строка. Нам надо число. Можно не изобретать велосипедов и затянуть функцию as-int из compojure.coercions. Правда, потребуется чуть-чуть изменить описание метода: (POST "/" [age :<< as-int] ???) Альтернативы? В них нет необходимости, реализация as-int предельно проста: (try (Long/parseLong s) (catch NumberFormatException _ nil)) Не видя её исходников ранее, я попытался написать код преобразования сам. Единственным отличием от as-int оказалось использование Integer/parseInt. И оно было ошибочным! Теперь считаем, достаточно ли юзер стар, и сообщаем об этом в шаблон (let [old-enough? (and (-> age nil? not) ; если число не распарсилось, придёт nil (< 18 age))] (функция-шаблончик old-enough?)) В шаблончике... ну, просто берёте и вместо одного из узлов DOM кладёте if. (defn функция-шаблончик [old-enough?] (html [:body (if old-enough? "YEAH" "NOPE")])) Примеры, конечно, совершенно примитивные. Но вы же можете их развить, верно? :)

Как настроить всплывающее окно с fancybox после нажатия button с

#php #javascript #form #fancybox #всплывающее_окно


Есть форма:



Подскажите плз, как после отправки формы открыть окно с блоком
на 5-10 секунд и пропадало, планирую сделать на fancybox Планирую использовать: $('#send').submit(function(e) { $.fancybox({ href: '#thx', modal: true }); return false; }); Но открытие так и не происходит....


Ответы

Ответ 1



Document
UPDATE $('.send').click(function() { var timeout = 5000; $.fancybox({ href: '#thx', openEffect: 'elastic', closeEffect: 'elastic' }); SetTimeout("parent.$.fancybox.close({ href: '#thx' });", timeout); setTimeout(function() { $.ajax({ type: $(this).attr('method'), url: $(this).attr('action'), data: $(this).serialize('#contact'), success: function(response) { console.log(response) }, }); }, timeout); });

Ответ 2



Решил сам: в конце php функции добавил код sleep(5); а скрипт такой: $('.send').click(function() { $.ajax({ type: $(this).attr('method'), url: $(this).attr('action'), data: $(this).serialize('#contact'), success: function(data) { $.fancybox({ href: '#thx', openEffect: 'elastic', closeEffect: 'elastic', afterLoad: function() { setTimeout(function() { parent.$.fancybox.close({ closeEffect: 'elastic' }); }, 3000); } }); } }); }); может кому пригодится....

Как подключить Android телефон к AndroidStudio Ubuntu

#android #linux #ubuntu #mobile


Все сделал согласно этой инструкции... 

Подключаю через usb свой HTC и появляется такое сообщение 


  Unable to mount Android Phone,


а потом еще такое окно


  Unable to open a folder for Android Phone


а потом такое


  Unable to find the requested file. Please check the spelling and try again.


и конечно же Android Studio не видит подключения... 

lsusb выводит:

aleksey@aleksey:~$ lsusb
Bus 003 Device 005: ID 0bda:0129 Realtek Semiconductor Corp. RTS5129 Card Reader
Controller
Bus 003 Device 006: ID 0cf3:0036 Atheros Communications, Inc.
Bus 003 Device 003: ID 0c45:670b Microdia
Bus 003 Device 002: ID 8087:8000 Intel Corp.
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

    


Ответы

Ответ 1



Откройте эмулятор терминала и наберите: lsusb С телефоном и без телефона и найдите разницу. Если разницы нет, либо дело в кабеле, либо в настройках смартфона. В моём случае это строка: Bus 002 Device 045: ID 0bb4:0c03 HTC (High Tech Computer Corp.) Первую группу цифр (0bb4) следует вставить вначале в /etc/udev/rules.d/51-android.rules: SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666" Затем в ~/.android/adb_usb.ini с префиксом 0x. Некоторые значения adb знает сам, тогда вторая строка может не понадобиться, но мешать не будет: # ANDROID 3RD PARTY USB VENDOR ID LIST -- DO NOT EDIT. # USE 'android update adb' TO GENERATE. # 1 USB VENDOR ID PER LINE. 0x2207 0x0bb4

Правильное хранение лайков/дислайков (голосования) в БД

#mysql #база_данных #хранение_данных


Есть сайт, на котором должна быть организована система голосования (лайк/дислайк).
Если записывать в БД информацию в виде номер_записи - id_пользователя, то вроде бы
всё хорошо. Но. Возьмем 100 записей и 100 пользователей. Каждый из них проголосует
за каждую запись, в итоге в БД будет содержаться 10.000 записей, а это проблема.
Почитав немного, изменил таблицу и она стала вида:
номер_записи - id_всех_пользователей_которые_голосовали. При тех же условиях вместо
10.000 получим всего 100 записей в БД.

Добавление нового id пользователя происходит так:


забираем всю строку из БД, где номер записи равен N
SELECT FROM WHERE users_id LIKE '%id_пользователя%' - запрос,
чтобы проверить существование уже этого id в строке
в случае успешной проверки добавляем в конец строки новый id и
заносим в БД новую строку.


Насколько это правильный подход к хранению такого рода информации? Какие есть альтернативы?
Готов услышать и принять к сведению.
    


Ответы

Ответ 1



Прикинем, как часто что требуется. сумма (или две суммы: за и против) по конкретному голосованию – супер-часто – при каждом открытии страницы с этим голосованием. голосовал ли данный юзер за данный опрос? – реже, при приёме нового голоса. кто проголосовал за / против за данный вопрос? – ещё реже, если вообще это открытая инфа. как и где голосовал данный юзер – тоже, вероятно, совсем редко, если вообще. Итого, текущие суммы храним в каком-нибудь быстром кэше, типа memcached/apc/redis. При поступлении нового голоса в БД надо проверить, голосовал ли? и сохранить голос + обновить кэшированную сумму. Хорошо иметь отдельную таблицу только для голосов: id_опроса id_юзера голос_плюс_минус (1 бит) Основной индекс составной - по обоим id - т.к. будем искать и по вопросу-юзеру (можно ли принять голос - может быть только одна запись с парой qid,uid) и по опросу (кто-как). И ещё индекс только по юзеру (где голосовал). Да, будет запись в БД и двух индексах на каждый отданный голос. Хоть 10 млн. – это нормально. Каждая запись – два 32-битных целых и 1 бит. Когда проект вырастет – станете горизонтально масштабировать – скажем, id опросов меньше X уедут на доп. MySQL сервер.

Как повернуть img, чтобы границы img остались в пределах div?

#javascript #html #css #css3


На странице есть следующий html: 

Если с помощью jquery: $('#img').css('transform','rotate(90deg)'); повернуть img на 90 градусов, то его граница выходит за пределы div. Как повернуть тег img, чтобы его граница оставалась внутри div? При этом высота div может меняться, а ширина должна остаться без изменений. И как из кода на JavaScript создать/изменить изображение в теге img без загрузки файла?


Ответы

Ответ 1



div { border: 1px dotted red; text-align: center; margin: 1em; overflow-y: hidden; /* Убираем лишнее пространство, если высота больше ширины */ } span { display: inline-block; vertical-align: top; } span:before { content: ""; display: inline-block; vertical-align: top; padding-top: 100%; } img { display: inline-block; vertical-align: top; transform: rotate(90deg) translateY(-50%); transform-origin: 0 0; position: relative; left: 50%; margin-bottom: -10000px; /* Значение заведомо больше высоты */ }


Ответ 2



Вариант со скриптом для произвольного угла поворота: function rotateImg(img, angle) { var width = img.clientWidth, height = img.clientHeight; var sina = Math.sin(angle), cosa = Math.cos(angle); img.style.transform = "rotate(" + angle + "rad)"; img.style.left = height*sina + "px"; var parentStyle = img.parentElement.style; parentStyle.width = width*cosa + height*sina + "px"; parentStyle.height = width*sina + height*cosa + "px"; } div { border: 1px dotted red; text-align: center; margin: 1em; } span { display: inline-block; vertical-align: top; text-align: left; border: 1px dotted green; overflow: hidden; /* Избавляемся от лишнего пространства */ } img { display: inline-block; vertical-align: top; transform-origin: 0 0; position: relative; }


Ответ 3



Что бы картинка оставалась в границах и не выступала делай диву overflow: hidden; А на JavaScript создать картинку так var newImg = document.createElement('img');//Создали пустой тег newImg.src = 'http://fafa.ru/image.png';// Установили аттрибут src newImg.width = 100; newImg.height = 100;

Ответ 4



html,body{ overflow:hidden; } .red-border{ width:300px; height:300px; border:1px solid red; margin:50px auto; position:relative; transition:1s; background:red; } .orange-border{ width:200px; height:200px; border:1px solid orange; position:absolute; top:50%; left:50%; margin-top:-100px; margin-left:-100px; border-radius:200px; line-height:200px; text-align:center; transition:.8s; background:orange; } .red-border:hover{ transform:rotate(-180deg); } .red-border:hover .orange-border{ transform:rotateY(-360deg); }
Hover Effect
исправил ответ - так ?

Как отобразить символ рубля на версии Android > 4?

#android


На Android > 5.0, все хорошо. Пробовал как мне кажется все советы со stackoverflow,
символ либо не отображается, либо отображается квадрат. Использую эмуляторы Genymotion. 
Вот моя тестовая активность:

public class MainActivity extends AppCompatActivity {

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

        TextView textView1 = (TextView)findViewById(R.id.textView1);
        TextView textView2 = (TextView)findViewById(R.id.textView2);
        TextView textView3 = (TextView)findViewById(R.id.textView3);
        TextView textView4 = (TextView)findViewById(R.id.textView4);
        TextView textView5 = (TextView)findViewById(R.id.textView5);

        Typeface typeface = Typeface.createFromAsset(getAssets(), "Roboto-Regular.ttf");
        textView1.setTypeface(typeface);
        textView2.setTypeface(typeface);
        textView3.setTypeface(typeface);
        textView4.setTypeface(typeface);
        textView5.setTypeface(typeface);

        String test1 = "100 $";
        String test2 = "200 \u20BD";
        String test3 = "300 \\u20BD";
        String test4 = "400 ₽";
        String test5 = "500 ₽";

        //textView1.setText(Html.fromHtml(getString(R.string.test_1)));
        //textView2.setText(Html.fromHtml(getString(R.string.test_2)));
        //textView3.setText(Html.fromHtml(getString(R.string.test_3)));
        //textView4.setText(Html.fromHtml(getString(R.string.test_4)));
        //textView5.setText(Html.fromHtml(getString(R.string.test_5)));

        textView1.setText(Html.fromHtml(test1));
        textView2.setText(Html.fromHtml(test2));
        textView3.setText(Html.fromHtml(test3));
        textView4.setText(Html.fromHtml(test4));
        textView5.setText(Html.fromHtml(test5));

        //textView1.setText(test1);
        //textView2.setText(test2);
        //textView3.setText(test3);
        //textView4.setText(test4);
        //textView5.setText(test5);
    }
}


Что я делаю не так?
    


Ответы

Ответ 1



Возьмите последнюю версию шрифта Roboto Regular из официального репозитория: https://github.com/google/roboto/blob/master/src/hinted/Roboto-Regular.ttf На сайте Android design сейчас выложена его устаревшая версия, в ней нет начертаний большинства символов валют.

Синхронизация проектов Eclipse через git

#java #git #eclipse


Как лучше синхронизировать проекты Eclipse между разными машинами на разных ОС?

Принципы работы git ясны, репозиторий имеется, однако есть некоторые сложности:


Проекты эклипса на разных ос конфигурируются по-разному. Поэтому все служебные файлы
приходится заносить в gitignore, так велит gitignore.io
Импортировать проект эклипса без служебных файлов на другой машине уже не получается.
Импортируется обычный проект, без buildpath и прочих плюшек. Конвертировать его в java
проект невозможно.


Каким образом можно наладить систему, чтобы на каждой машине был проект?
    


Ответы

Ответ 1



Решение из англоязычного раздела. Импортируйте, как обычный проект Обратите внимание, что импортируемые данные не являются проектом Eclipse (нет build path) Откройте/создайте.project файл в папке импортированного проекта. Перейдите во раздел source Найдите и измените на org.eclipse.jdt.core.javanature и сохраните файл Правый клик в Eclipse на папке src, перейдите в Build Path... и кликните Use as Source Folder https://stackoverflow.com/a/32407205/5244594 Для большего теоретического удобства в будущем стал работать с проектом maven, а не с проектом Eclipse. Больше универсальности и переносимости. При импорте проекта maven следует импортировать, как Existing Maven Project. Eclipse сам определяет, что проект принадлежит git. В итоге мы имеем проект с автоматическим контролем зависимостей, находящийся в git-репозитории, что позволяет синхронизировать проект не только между машинами, но и между различными IDE, поддерживающими maven.

Правильно ли помещать логику ввода данных с консоли в конструктор?

#java


Задание: "Реализовать программу учета среднесуточной температуры на протяжении месяца.
Ввод данных реализовать с консоли."
Что правильнее:


Поместить в конструктор по умолчанию логику ввода данных с консоли со всеми валидациями?
Создать отдельный метод для ввода данных, затем создавать объект класса, и к нему
применять этот метод?


У меня сейчас вот так в конструкторе:

public TemperatureRecords() {
    System.out.println("Введите название месяца:");
    setMonth(input.nextLine().toLowerCase());
    while (getDaysAmount()!=0) {
        System.out.printf("Введите температуру %d числа:%n", temp);

        try {
            setTemperature(input.nextInt());
            setDaysAmount(getDaysAmount()-1);
        } catch (Exception e) {
            System.out.println("Ошибка!");
            input.skip(".*");
        }
    }
}

    


Ответы

Ответ 1



Определённо, нет. То, как это реализовано у вас - явно неправильно. В вашем случае конструктор класса и сам класс зависят от консольного ввода. Вообще зависимости между классами - вещь не очень хорошая, а зависимости настолько явные и того хуже. В данном случае мы имеем вот какую проблему: ваш класс не может работать без консоли, хотя не имеет к ней ни малейшего отношения. Представьте, что вам понадобилось использовать этот класс в каком-то другом приложении, где взаимодействие с пользователем происходит не через консоль, а каким-то другим способом (страница в браузере, форма десктопного приложения или как-то ещё). Вы не сможете корректно создать экземпляр вашего класса, и конструктор потребуется переписывать (или добавлять ещё один) чтобы он мог принимать данные не из консоли. Это говорит о том, что конструктор должен принимать необходимые данные в качестве параметров, класс можно будет безболезненно использовать о куда угодно. Как-то так: public TemperatureRecords(String month, int[] temperatureData) { setMonth(month); for(int value : temperatureData) { setTemperature(value); setDaysAmount(getDaysAmount()-1); } } Дело даже не в том, что конструктор стал вдвое короче (вырезанный из него код все равно должен будет использоваться, только в другом месте), а в том, что он во-первых, стал проще, а в-вторых, и в-главных, он теперь получает только те данные, которые ему нужны, знать ничего не знает ни о каких классах, которые не имеют к нему отношения и, следовательно, может быть вызван откуда угодно. Логику же получения данных от пользователя и их валидацию правильнее будет возложить на другой код, разделив тем самым логику вашего класса и логику получения для него данных (да-да, старый принцип "разделяй и властвуй" никто не отменял).

проблема с наследованием через конструктор

#javascript


пример наследования:

есть 2 конструктора: Game, Level. на их основе я создаю 2 объекта, таким образом,
чтобы level наследовался от game:

var Game = function(parentGameElementTag) {
  this.parentGameElementTag = parentGameElementTag;
  this.gameElementId = 'game';
  this.levelObj = new Level();  

  this.init();
};

Game.prototype = {
  init: function() {  
    $('
').appendTo(this.parentGameElementTag); } }; var Level = function() { var self = this; this.fieldElementId = 'field'; this.levelScreenDisplay('body'); }; //Level.prototype = Game; Level.prototype = Object.create(Game.prototype); Level.prototype = { levelScreenDisplay: function(parentElementTag) { $('
Уровень: ' + this.level + '
').appendTo(parentElementTag); setTimeout(function() { $('
Нажмите любую клавишу для старта
').appendTo('#levelBeginLabel'); document.onkeypress = function() { document.onkeypress = undefined; $('#levelBeginLabel').remove(); }; }, 1000); } }; var app = new Game('body'); в результате на странице должен выводиться номер уровня. которого нет в level, но который есть в game. а благодаря наследованию он должен найтись. но не находится. в чём я ошибаюсь?


Ответы

Ответ 1



Основная проблема в том, что свойства level нет ни в одном из классов поэтому всегда выводится undefiend. Кроме того в данном случае не нужно наследование. Проще указать это свойство через конструктор. var Game = function(parentGameElementTag) { this.parentGameElementTag = parentGameElementTag; this.gameElementId = 'game'; this.levelObj = new Level(1); this.init(); }; Game.prototype = { init: function() { $('
').appendTo(this.parentGameElementTag); } }; var Level = function(level) { var self = this; this.level = level; this.fieldElementId = 'field'; this.levelScreenDisplay('body'); }; Level.prototype = { levelScreenDisplay: function(parentElementTag) { $('
Уровень: ' + this.level + '
').appendTo(parentElementTag); setTimeout(function() { $('
Нажмите любую клавишу для старта
').appendTo('#levelBeginLabel'); document.onkeypress = function() { document.onkeypress = undefined; $('#levelBeginLabel').remove(); }; }, 1000); } }; var app = new Game('body'); .level_begin_label { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; background: #000; padding-top: 20px; color: #fff; text-align: center; font: 20px arial, sans-serif; } .any_key_invitation { margin-top: 10px; font-size: 16px; } .game { /* position: absolute; top: 0; left: 0; right: 0; bottom: 0;*/ z-index: 10; position: relative; background: #000; width: 300px; height: 100%; margin: 0 auto; padding-top: 40px; color: #fff; } UPDATE: обновление после комментария. В данном случае проще всего сохранить ссылку на Game внутри создаваемого объекта Level. var Game = function(parentGameElementTag) { this.parentGameElementTag = parentGameElementTag; this.gameElementId = 'game'; this.level = 1; //например this.levelObj = new Level(this); // передаем ссылку game объекта в конструктор для уровня this.init(); }; Game.prototype = { init: function() { $('
').appendTo(this.parentGameElementTag); } }; var Level = function(game) { var self = this; this.level = game.level; // можно опустить эту строучку и получать значение через this.game.level this.game = game; this.fieldElementId = 'field'; this.levelScreenDisplay('body'); }; Level.prototype = { levelScreenDisplay: function(parentElementTag) { $('
Уровень: ' + this.level + '
').appendTo(parentElementTag); setTimeout(function() { $('
Нажмите любую клавишу для старта
').appendTo('#levelBeginLabel'); document.onkeypress = function() { document.onkeypress = undefined; $('#levelBeginLabel').remove(); }; }, 1000); } }; var app = new Game('body'); .level_begin_label { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; background: #000; padding-top: 20px; color: #fff; text-align: center; font: 20px arial, sans-serif; } .any_key_invitation { margin-top: 10px; font-size: 16px; } .game { /* position: absolute; top: 0; left: 0; right: 0; bottom: 0;*/ z-index: 10; position: relative; background: #000; width: 300px; height: 100%; margin: 0 auto; padding-top: 40px; color: #fff; }

Ответ 2



// для определения наследования var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Game = (function () { function Game(tag) { this.init(); } Game.prototype.init = function () { // ... }; Object.defineProperty(Game.prototype, "LevelNumber", { get: function () { return 123; }, enumerable: true, configurable: true }); return Game; })(); // Level наследует Game var Level = (function (_super) { __extends(Level, _super); function Level(tag) { _super.call(this, tag); } return Level; })(Game); var lvl = new Level("body"); alert(lvl.LevelNumber); // выводит: 123 -- LevelNumber определен в Game

Android/Java. Как делается диалог чата с разделением на правую и левую стороны?

#android #listview #view #adapter #chat


Как сделать диалог Чата такого вида?



Вот чтобы справа и слева отображалось при приеме и отправке соответственно..

Если бы там только текст был.. то можно было бы Gravity применять.. а там еще картинка..
это получается как то надо две заготовки и скрывать их????

или как то кастомные адаптеры создать? Если есть, приведите подобные кусочки кода..

У меня код такой:

public static class MySimpleAdapter extends SimpleAdapter {

   private List> results;
   private Context mContext;

   public MySimpleAdapter(Context context, List> data, int
resource, String[] from, int[] to) 
    {
        super(context, data, resource, from, to);
        this.results = data;
        this.mContext = context;

    }

     public View getView(int position, View view, ViewGroup parent)
     {
        View v = view;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            v = vi.inflate(R.layout.mymsg, null);
        }


        if (!results.get(results.size()-1).containsKey("to")) 

        {           
        TextView tt = (TextView) v.findViewById(R.id.mytxt);
        tt.setText(results.get(results.size()-1).get("msg"));
        v.findViewById(R.id.mymsg).setVisibility(View.VISIBLE);
        v.findViewById(R.id.memsg).setVisibility(View.GONE);

        }
        else
        {

        TextView tt= (TextView) v.findViewById(R.id.metxt);
        tt.setText(results.get(results.size()-1).get("msg"));

        v.findViewById(R.id.mymsg).setVisibility(View.GONE);
        v.findViewById(R.id.memsg).setVisibility(View.VISIBLE);
        }

        return v;
    }
}


И код отправки/приема:

HashMap map = new HashMap(); 
try {
Message message = new Message();
message.setBody(msg.getText().toString()+ "\n");
sendMessage(message);
map.put("msg", message.getBody().toString());
map.put("to", message.getTo().toString());
usersList.add(map);
sadapter =  new MySimpleAdapter(getActivity(),  usersList, R.layout.mymsg, from, to);
listView.setAdapter(sadapter);
sadapter.notifyDataSetChanged();
} catch (NotConnectedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

    


Ответы

Ответ 1



План следующий: 1 - создать два типа леяута, для отображения исходящего и входящего сообщения 2 - в адаптере переопределить метод public int getItemViewType(int position) {} 3 - в onBindViewHolder инитить данные

Как правильно: Object.ReferenceEquals или Оператор ==?

#c_sharp #net


Как правильно сравнить два объекта, чтобы определить являются ли экземпляры  объектов
одним и тем же экземпляром или нет?
Что правильно/лучше использовать: метод Object.ReferenceEquals 

if(Object.ReferenceEquals(a, b)) { /*...*/ }


или Оператор == 

if(a == b) { /*...*/ }      // object a, b;




ВНИМАНИЕ: не путайте Equals c ReferenceEquals
    


Ответы

Ответ 1



Мне кажется, здесь более важна не техническая сторона вопроса, а читабельность кода. Если у вас есть два объекта a и b, и вы сравниваете их через ==, может быть вызван не operator == (object, object), а перегруженный оператор сравнения. Это значит, что семантика == шире, чем простое сравнение ссылок. Если ваша цель — распознать именно один и тот же экземпляр, я бы посоветовал использовать именно ReferenceEquals, т. к. при этом вы прямо «говорите» то, что хотите. Преимущество в компактности кода у ==, на мой взгляд, даёт недостаточный выигрыш по сравнению в преимуществе в понятности кода. Да и для правильности сравнения нужно приведение типа к object, которое тоже не добавляет краткости. С другой стороны, если вам нужно установить не равенство ссылок, а логическую тождественность объектов, для этого более правильным может оказаться использование (возможно перегруженного) оператора ==. Поэтому используйте то, что вам нужно. Универсального совета нет, каждый из методов имеет своё применение. Ещё одна техническая деталь — в обобщённых (generic-) методах на текущий момент (C# 6) невозможно сообщить компилятору, что у типа есть оператор ==. Поэтому сравнение через == в generic-методе может дать не такой же результат, как в обычном методе.

Ответ 2



В исходнике .NET Framework, метод Object.ReferenceEquals определен следующим образом: public static bool ReferenceEquals (Object objA, Object objB) { return objA == objB; } В методе вызывается Оператор ==, значит если сравнивать Object'ы, то нет разницы. Реализация Equals следующая public static bool Equals(Object objA, Object objB) { if (objA==objB) { return true; } if (objA==null || objB==null) { return false; } return objA.Equals(objB); } ВНИМАНИЕ: если Оператор == вернет false, то может быть вызван метод public virtual bool Equals(Object obj) -- метод виртуальный, может быть переопределен в производных классах и полагаться на него не надо. Для идентификации можно использовать метод RuntimeHelpers.GetHashCode using System.Runtime.CompilerServices; if(RuntimeHelpers.GetHashCode(a) == RuntimeHelpers.GetHashCode(b)) { /*... */ } ВНИМАНИЕ: если a и b это строки, то RuntimeHelpers.GetHashCode для одинаковых строк может вернуть разные хэш-коды. Например, var s1 = "321"; var s2 = String.Concat(new List { "3", "2", "1" }); var r1 = s1 == s2; // true var r2 = RuntimeHelpers.GetHashCode(s1) == RuntimeHelpers.GetHashCode(s2); // false Дело в том, что литералы (строки, определенные в коде, такие как "321"), добавляются во внутренний пул строк в целях экономии памяти. А строки, собранные из частей, в пул не добавляются. Поэтому получается, что s1 и s2 - разные объекты. Но s2 можно интернировать (т.е. добавить в пул строк) s2 = String.Intern(s2); Т.к. в пуле строк уже есть s1, то s2 и s1 будут указывать на один и тот же строковой объект, поэтому хэш-коды у s1 и s2 станут равны. var r3 = RuntimeHelpers.GetHashCode(s1) == RuntimeHelpers.GetHashCode(s2); // true

Низкочастотная фильтрация изображений (книга Гонсалеса “Цифровая обработка изображений”)

#java #изображения


Я пытаюсь реализовать на java низкочастотную фильтрацию изображений.

Реализую по книге Гонсалеса "Цифровая обработка изображений" следущие пункты (стр.
245):  


Исходное изображение умножается на "(-1)^(x+y)", чтобы его фурье-преобразование оказалось
центрированным;  
Вычисляется прямое ДПФ F(u,v) изображения, полученного после шага 1;  
Ф-ция F(u,v) умножается на ф-цию фильтра H(u,v);  
Вычисляется обратное ДПФ от результата шага 3;  
Вычисляется вещественная часть результата шага 4;  
Результат шага 5 умножается на (-1)^(x+y) 


Чисто для примера, решила реализовать "Идеальный фильтр низких частот" (стр.257).
Как я понимаю, результат получается неправильным с самого первого шага.

Что я делаю не так?

Прикладываю код каждого шага и результаты обработки на каждом шаге.

Моя реализация шагов:

1)

double funcXY;
Complex[][] arrOnStepOne = new Complex[bufferedImage.getWidth()][bufferedImage.getHeight()];
for (int x = 0; x < bufferedImage.getWidth(); x++) {
    for (int y = 0; y < bufferedImage.getHeight(); y++) {
        funcXY = (Math.pow(-1.0, (x + y))) * bufferedImage.getRGB(x, y);
        Complex complexFuncXY = new Complex(funcXY, 0);
        arrOnStepOne[x][y] = complexFuncXY;
    }
}


2)

int width = arrOnStepOne.length;
int height = arrOnStepOne[0].length;
Complex sumByX = new Complex(0, 0);
Complex sumByY = new Complex(0, 0);
Complex[][] complexFurje = new Complex[width][height];
for (int u=0; u <= width-1; u++) {
    for (int v = 0; v <= height-1; v++) {
        sumByX = new Complex(0, 0);
        for (int x = 0; x <= width - 1; x++) {
            sumByY = new Complex(0, 0);
            for (int y = 0; y <= height - 1; y++) {
                Double teta = -2 * Math.PI * ((u * x / (double) width) + (v * y /
(double) height));
                Complex complexE = new Complex(Math.cos(teta), Math.sin(teta));
                sumByY = sumByY.Add(arrOnStepOne[x][y].Mult(complexE));
            }
            sumByX = sumByX.Add(sumByY);
        }
        complexFurje[u][v] = sumByX.Div(new Complex(width*height, 0));
    }
}


3)

int d0;
int nPow = 2;
double d;
double filtrD;
double filtrH;
Complex[][] complexFiltr = new Complex[width][height];

for (int u=0;u <= width-1; u++) {
    for (int v = 0; v <= height-1; v++) {
        d = Math.pow((u - width / 2.), 2) + Math.pow((v - height / 2.), 2);
        filtrD = Math.pow(d, 1. / 2); //D(u,v)
        d0 = 80;
        filtrH = 1 / (1 + Math.pow(filtrD / d0, 2. * nPow));
        complexFiltr[u][v] = new Complex(filtrH, 0).Mult(complexFurje[u][v]);
    }
}


4)

for (int x = 0; x <= width-1 ; x++) {
    System.out.println("X = " + x +" / " + (width-1) + ".");
    for (int y = 0; y <= height-1 ; y++) {
        sumByU = new Complex(0, 0);

        for (int u = 0; u <= width-1; u++) {
            sumByV = new Complex(0, 0);
            for (int v = 0; v <= height - 1; v++) {
                Double teta = 2 * Math.PI * (x * u / (double) width + y * v / (double)
height);
                Complex complexE = new Complex(Math.cos(teta), Math.sin(teta));
                sumByV = sumByV.Add(complexE.Mult(complexFiltr[u][v]));
            }
            sumByU = sumByU.Add(sumByV);
        }
        funcStep4XY[x][y]=sumByU;
    }
}


5,6)

for (int x = 0; x <= width-1; x++) {
    for (int y = 0; y <= height-1; y++) {
        funcStep5XY[x][y] = funcStep4XY[x][y].getdReal();
        funcStep5XY[x][y] *= Math.pow(-1.0,x+y);
    }
}



Ссылка на саму книгу здесь
    


Ответы

Ответ 1



Судя по артефактам на step1.jpg, вычисления производятся в целых числах. При этом происходит переполнение вместо сатурации, из-за чего вместо "засветки" белым цветом можно увидеть чёрные пиксели. В результате ДПФ step2.jpg вместо белой "звезды" на чёрном фоне выглядит как случайный шум, образованный всё теми же искажениями переполнения. Ну, и в итоге после ОДПФ получается сильно зашумленное изображение step56.jpg. Просто не хватает разрядности при вычислениях. Например, нужно 35 бит, а используется 32 бита.

Cкачать (fetch) с GitLab содержимое запроса на слияние (merge request)

#git #gitlab #git_remote


Сервер Gitlab, организую работу через запросы на слияние (merge request, pull request).

При создании запроса хотелось бы иметь URL, из которого Jenkins смог бы выкачивать
последний коммит ветки, которая предлагается к слиянию.

Есть ли возможность в Gitlab получить такой URL?


какой-нибудь alias к ветке, предлагаемой к слиянию?
автоматически создаваемый предварительный коммит? (т.е. что бы получилось, если прямо
сейчас нажать кнопку Merge Request?


Знаю, что-то подобное возможно в Gitlab CI и GitHub CI, на этих коммитах даже тесты
прогоняются. Поэтому возможен и третий вариант:


Работать с Jenkins как с Gitlab CI?


Перейти полностью на Gitlab CI - не вариант, это будут неоправданные затраты.
    


Ответы

Ответ 1



автоматически создаваемый предварительный коммит? (т.е. что бы получилось, если прямо сейчас нажать кнопку Merge Request? Фича пока не реализована, можно проголосовать. какой-нибудь alias к ветке, предлагаемой к слиянию? Реализовано. На каждый merge request гитлаб создаёт внутри себя отдельный указатель в refs/merge-requests. Нужно просто настроить свой репозиторий, чтобы при git fetch забирать эти указатели. Открываем .git/config, находим в нём блок, соответствующий репозиторию. [remote "origin"] url = https://gitlab.com/gitlab-org/gitlab-ce.git fetch = +refs/heads/*:refs/remotes/origin/* Добавляем в него строку +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*. Теперь должно выглядеть так: [remote "origin"] url = https://gitlab.com/gitlab-org/gitlab-ce.git fetch = +refs/heads/*:refs/remotes/origin/* fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/* Обновляем данные: $ git fetch origin From https://gitlab.com/gitlab-org/gitlab-ce.git * [new ref] refs/merge-requests/1/head -> origin/merge-requests/1 * [new ref] refs/merge-requests/2/head -> origin/merge-requests/2 Теперь можно создать новую локальную ветку, отслеживающую соответствующий merge request. $ git checkout merge-requests/1 Branch merge-requests/1 set up to track remote branch merge-requests/1 from origin. Switched to a new branch 'merge-requests/1' Примеры взяты из документации GitLab. Там же есть более подробные инструкции.

Асинхронный вызов метода в WPF

#c_sharp #wpf #async_await


У меня имеется WPF-приложение, работающее с базой данных. Количество записей в базе
довольно большое и постоянно растёт. В проекте используется ORM(EF 6).
Имеется некий класс, работающий непосредственно с контекстом базы данных:

public class Store : IStore {...}


В интерфейсе класса определён ряд методов, код в которых обращается непосредственно
к базе через EF-контекст, соответственно, выполнение метода занимает довольно длительное
время, что может вызвать простой интерфейса пользователя, если я всё правильно понимаю.
Следовательно, нужно вынести операции получения данных из базы в отдельные потоки.
Так, скажем, в Store определен метод:

public ICollection GetAllProducts() {...}


Если я правильно понимаю, мне необходимо добавить его асинхронную реализацию:

public async Task> GetAllProductsAsync()
{
    return await Task>.Factory.StartNew(GetAllProducts)
}


Как правильно воспользоваться таким методом в самом приложении в ViewModel, Скажем,
чтобы, пока данные загружаются, в StatusBar отображался прогресс загрузки данных, а
DataGrid отобразил результат как только данные загрузятся?
    


Ответы

Ответ 1



Окей, давайте начнём с Task.Factory.StartNew. Это нужно только если ваш запрос к базе данных не поддерживает асинхронность сам, и требует выделения отдельного потока (кстати, лучше писать просто Task.Run). Для свежего Entity Framework это не так, асинхронные функции поддерживаются правильно, из коробки: Entity Framework tutorial: async query and save. С асинхронностью на уровне базы данных вам не нужно создавать отдельные потоки. По поводу прогресса, с этим хуже. EF не поддерживает информацию о прогрессе операции, так что вы можете просто вывести состояние «читаю», и считывать до тех пор, пока не закончите. В случае, когда/если будет имплементирована поддержка прогресса, вам можно будет воспользоваться интерфейсом IProgress. Таким образом, код в VM будет выглядеть так: IsLoading = true; var localData = await model.LoadDataAsync(); IsLoading = false; Data = localData; Скорее всего, вы не захотите выкладывать модельные классы для View, поэтому вам понадобится обёртка, создающая VM-объекты для ваших entity: // в модели IQueryable GetData(); // в VM IsLoading = true; var localData = new List(); await model.GetData().ForEachAsync(entity => localData.Add(new EntityVM(entity)); IsLoading = false; Data = localData; Ну и, как верно отмечает @Pavel Mayorov, возможно вы захотите ловить исключения, так что вам понадобится try: IsLoading = true; var localData = new List(); try { await model.GetData().ForEachAsync(entity => localData.Add(new EntityVM(entity)); Data = new ObservableCollection(localData); } catch { IsFailed = true; throw; } finally { IsLoading = false; } Или, если вы хотите, чтобы данные появлялись не все вместе, а по мере подгрузки, наверное подойдёт просто await model.GetData().ForEachAsync(entity => Data.Add(new EntityVM(entity)); (но здесь я не уверен, т. к. ни разу не пробовал).

Сервис отключается при засыпании телефона

#java #android #service


Код сервиса, который каждую минуту запускает вибрацию на телефоне.
Как только экран гаснет, сервис прекращает работу. Как запретить остановку? И как
в нужный момент по кнопке остановить этот сервис?

    public class TimeService extends Service {
Vibrator vib;
public static final long NOTIFY_INTERVAL = 60 * 1000; // 60 seconds
private Handler mHandler = new Handler();
private Timer mTimer = null;

@Override
public IBinder onBind(Intent intent) { return null; }

@Override
public void onCreate() {
    vib = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);

    // cancel if already existed
    if (mTimer != null) { mTimer.cancel();}
else { mTimer = new Timer(); }
    // schedule task
    mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0,
            NOTIFY_INTERVAL);
}

class TimeDisplayTimerTask extends TimerTask {

    @Override
    public void run() {
        // run on another thread
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                vib.vibrate(500);
            }
        });
    }


Запускаю сервис так:

public void onClick_btTask(View v) {
    startService(new Intent(this, TimeService.class));

}

    


Ответы

Ответ 1



Service по умолчанию работает в том же потоке, что и запускающая его activity. Чтобы вибрировать каждую минуту, можете попробовать использовать связку с IntentService и AlarmManager-а с ключом RTC_WAKEUP, который будет этот IntentService каждую минуту вызывать. Примерно так: public class VibrateService extends IntentService { public static final String TAG = "VibrateService"; public VibrateService() { super(TAG); } @Override protected void onHandleIntent(Intent intent) { Vibrator vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(500); } } ... Intent intent = new Intent(this, VibrateService.class); // Запуск повторения вызова сервиса AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60 * 1000, PendingIntent.getService(this, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)); Конечно же, VibrateService должен быть объявлен в манифесте, как и разрешение вибрировать:

Как оставить SearchView открытым

#android #android_search_view


У меня на ToolBar лупа - поиска. При клике SearchView раскрывается. Так вот мне нужно
сделать так чтобы он всегда был открым... Как сделать?







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


    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setDisplayShowTitleEnabled(false);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}


Activity:

@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);

    SearchManager searchManager =
            (SearchManager) getSystemService(Context.SEARCH_SERVICE);

    SearchView searchView =
            (SearchView) menu.findItem(R.id.action_search).getActionView();

    searchView.setIconifiedByDefault(false);
    searchView.setQueryHint("Поиск");

    searchView.setSearchableInfo(
            searchManager.getSearchableInfo(getComponentName()));

    return true;
}

    


Ответы

Ответ 1



If you want the search field to always be visible, then call setIconifiedByDefault(false). "Если вы хотите, чтоб поле поиска было всегда видимым, тогда вызовите(используйте) setIconifiedByDefault(false)" в xml android:iconifiedByDefault="false" программно: searchView.setIconified(false); Что касается именно вашего вопроса: в xml убедитесь, чтоб стояло showAsAction="always" а после программно, измените так: SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView(); searchView.setIconifiedByDefault(false);

Ответ 2



Проблема решилась: searchView.setIconifiedByDefault(**true**); а в XML: app:showAsAction="always"

Как упаковать несколько файлов в zip,которые лежат в разных папках?

#c_sharp #zip


Есть List в котором содержатся пути(Path) всех файлов, которые я хочу упаковать.

Проблема в том что эти файлы в разных папках. Можно как то скопировать их в новую
папку, а потом их упаковать, но количество этих файлов очень велико, так неудобно.

Есть ли какой нибудь способ?

Код создания архива:

using (ZipFile zip = new ZipFile())
{
    zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
    zip.AddDirectory(@"C:\project\");
    zip.AddFile(@"c:\Temp\Import.csv");
    zip.Save(@"C:\Temp\PackedProject.zip");
}

    


Ответы

Ответ 1



Приведенный вами код, к сожалению, не работоспособен. Класс ZipFile есть в библиотеке классов, но он статический и не рекомендован Microsoft для использования в приложениях для Windows Store, там же рекомендовано использовать класс ZipArchive. MSDN Если полные имена (путь+имя) файлов уже содержатся в List fileNames, то не важно в каких папках они находятся, главное чтобы были права на чтение этих файлов. Если все условия выполнены, то дальше все довольно просто: using System; using System.IO; using System.IO.Compression; using (FileStream zipToOpen = new FileStream(@"newArchive.zip", FileMode.OpenOrCreate)) { using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update)) { foreach (string fileName in fileNames) { FileInfo fi = new FileInfo(fileName) ZipArchiveEntry fileEntry = archive.CreateEntryFromFile(fi.FullName,fi.Name,CompressionLevel.Optimal); } } } как-то так. Более подробно читать в MSDN Можно улучшить результат если собирать файлы не в string, а сразу в FileInfo и List соответственно. Преимущество использования 'FileInfo' для хранения информации о файлах заключается в том, что есть ряд методов получения уже готовых коллекций этих объектов, например как дочерние узлы DirectoryInfo, и "из коробки" получаем легкие манипуляции с именами файлов. как то выделение пути из полного имени, получение только имени без пути плюс дополнительная функциональность, которая может внезапно понадобиться при работе с файлом. например уточнить права доступа.

Почему каждый раз перезаписывается значение в двумерном массиве строк?

#cpp #массивы #указатели


Необходима помощь в следующем:

char * UserData[4] = { new char[50], new char[50], new char[13], new char[4] };
char *** phoneBook = new char ** [10];

phoneBook[0] = UserData;
gets(UserData[0]);
gets(UserData[1]);
gets(UserData[2]);
gets(UserData[3]);

cout << phoneBook[0][2] << " Test string 1\n\n"; // Вывод стоки, здесь все хорошо.

phoneBook[1] = UserData;
gets(UserData[0]);
gets(UserData[1]);
gets(UserData[2]);
gets(UserData[3]);

// Вывод стоки, здесь всё хорошо.
cout << phoneBook[1][3] << " Test string 2\n\n"; 
// Значение перезаписалось! Почему?
cout << phoneBook[0][2] << " Test string 1\n\n WHY IS IT CHANGING???";



Проблема в том, что я как бы "перезаписываю" каждый раз значения, которые вводил
с клавиатуры.
Мне нужно сделать так, чтобы я имел возможность ввести массив данных 1, потом массив
данных 2 и потом сделать их вывод например. Как это можно сделать?

    


Ответы

Ответ 1



Указатели phoneBook ссылаются на один и тот же массив. phoneBook[0] = UserData; phoneBook[1] = UserData; Вам нужна структура Например: struct phoneBookStruct{ char UserData0[50]; char UserData1[50]; char UserData2[13]; char UserData3[4]; } Вот её вы можете использовать как массив phoneBookStruct phoneBook[10]; gets(phoneBook[0].UserData0); gets(phoneBook[0].UserData1); gets(phoneBook[0].UserData2); gets(phoneBook[0].UserData3); cout<

Ответ 2



Потому что, вы используйте один и тот же кусок данных -- UserData: phoneBook[0] = UserData; phoneBook[1] = UserData; phoneBook[0] и phoneBook[1] указывают на одни и те же данные И для c++ рекомендуется использовать std::string, а не char *

android ListView с кнопками. Как получить _id строки, на которой кликнута кнопка

#java #android


В общем есть список ListView, который я заполняю через SimpleCursorAdapter.
Инициализируется вот так:

String[] from = new String[] {"client_tel","timeToWashStart"};
int[] to = new int[] {R.id.client_tel,R.id.timeToWashStart};


scAdapter = new SimpleCursorAdapter(MainActivity.this, R.layout.item, null, from, to, 0);
lvData.setAdapter(scAdapter);

getSupportLoaderManager().initLoader(0, null, MainActivity.this);


Данные получаю через CursorLoader с MySQL, список формируется, все нормально.
Но в каждой строке списка есть кнопки, на которые нужно кликать.

Вот сам вопрос: как узнать _id или позицию строки, где была кликнута кнопка?

причем метод 

lvData.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, "position = " + position + " id= " + id, Toast.LENGTH_SHORT).show();
}
});


почему-то не работает...
и я никак не пойму как прописать метод getView() для адаптера.

Скажите в какую сторону думать, я уже запарился на месте топтаться)
Заранее благодарен за советы

ПС: весь код у меня реализован в одном классе, может это важно

public class MainActivity extends FragmentActivity implements CompoundButton.OnCheckedChangeListener,LoaderManager.LoaderCallbacks {

    


Ответы

Ответ 1



То, что не работает setOnItemClickListener, можно только догадываться. Выгрузите код, тогда будет ответ. Узнать позицию и id при нажатии на кнопку (cursorloader), можно разными вариантами, самый очевидный и простой на мой взгляд: Делаем кастомный SimpleCursorAdapter, находим нашу кнопку, вешаем слушатель. Далее получаем его родителя (элемент в списке) у этого элемента получаем родителя это и есть наш список и относительно их находим позицию в списке. Зная позицию получаем id: MyAdapter.class public class MyAdapter extends SimpleCursorAdapter { public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { super(context, layout, c, from, to, flags); } @Override public void bindView(View view, Context context, final Cursor cursor) { Button btn = (Button) view.findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { View parent_row = (View) v.getParent(); ListView lv = (ListView) parent_row.getParent(); final int position = lv.getPositionForView(parent_row); Log.d("...", "position = " + position); Log.d("...", "id = " + getItemId(position)); } }); super.bindView(view, context, cursor); } }

Ответ 2



Если подытожить, рабочий кусок кода: public class MainActivity extends FragmentActivity { public String LOG_TAG = "LOG_TAG"; public ListView lvData; public MyAdapter scAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); lvData = (ListView) findViewById(R.id.lvData); ///попробую тут адаптер инициализировать String[] from = new String[] {"client_tel","timeToWashStart"}; int[] to = new int[] {R.id.client_tel,R.id.timeToWashStart}; Log.d(LOG_TAG,"формируем адаптер"); // создааем адаптер и настраиваем список /// scAdapter = new SimpleCursorAdapter(MainActivity.this, R.layout.item, null, from, to, 0); scAdapter = new MyAdapter(MainActivity.this, R.layout.item, null, from, to, 0); lvData.setAdapter(scAdapter); // создаем лоадер для чтения данных http://startandroid.ru/ru/uroki/vse-uroki-spiskom/278-urok-136-cursorloader.html // по этой ссылке описано что делает следующая строка, это получение данных getSupportLoaderManager().initLoader(0, null, MainActivity.this); } И, как рекомендовал shwarz-andrei, создаем отдельный класс для адаптера public class MyAdapter extends SimpleCursorAdapter { public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { super(context, layout, c, from, to, flags); } @Override public void bindView(View view, Context context, final Cursor cursor) { final ImageView img = (ImageView) view.findViewById(R.id.ivImg); img.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { View parent_row = (View) v.getParent(); ListView lv = (ListView) parent_row.getParent(); final int position = lv.getPositionForView(parent_row); Log.d("...", "position = " + position); Log.d("...", "id = " + getItemId(position)); } }); super.bindView(view, context, cursor); } }

Можно ли и как совмещать лицензии GPL 2+ и MIT?

#лицензирование #gnu


Я пишу Open Sourse проект под лицензией GNU GPL 2+, используя в проекте инструменты,
которые распространяются по лицензии MIT. Это, собственно, сам фреймворк, на котором
разрабатывается проект и отдельные модули с программным кодом.

Можно ли и как совмещать эти две лицензии?

В своих проектах я держу папку LICENSE, в которой находятся оригинальный текст лицензии
GNU GPL 2+ и ее текст на русском. При первом запуске проекта первым делом я всегда
вывожу окошко, что мол, приложение распространяется под такой-то лицензией, с текстом
которой можно ознакомиться и "бла-бла-бла"... В библиотеках своего проекта также указано,
что они распространяются под лицензией GNU GPL 2+.

Достаточно ли будет указать в том же окне, при первом запуске проекта, что программа
написана с использованием таких-то инструментов с лицензией MIT? Или же мне снабжать
каждый модуль, который я использую в проекте шапкой текста лицензии MIT?

Хотелось бы уточнить эти моменты.
    


Ответы

Ответ 1



Что такое MIT лицензия? Так называемая "лицензия MIT" это обобщённое название двух лицензий X11 и Expat. Их единственное различие состоит в наличие одного абзаца в X11, который запрещает рекламировать X Consortium без его разрешения, а в Expact он соответственно отсутствует. Что разрешает данная лицензия? В принципе всё, при условии что текст лицензии будет включен во все распространяемые копии или значительные части ПО. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Можно ли совмещать GNU GPL и MIT лицензии? Да. MIT является совместимой с GNU GPL. Cписок совместимых лицензий с GNU. Как совмещать? Просто гарантировать, чтобы в используемых Вами инструментах и библиотеках под лицензией MIT присутствовал текст самой этой лицензии. Каких-либо дополнительных действий в виде отображения их в окне приветствия Вашего проекта не требуется. Однако, Вы можете упомянуть об используемых библиотеках в файле LICENSE в корневом каталоге проекта. Например в проекте GIMP-2.8 помимо основного файла COPYING с лицензией GNU GPL v3, присутствует файл LICENSE в котором даётся пояснение, что некоторые библиотеки проекта (а именно libgimp) имеют другую лицензию отличную от GNU GPL v3 (естественно, совместимую с ней): The GIMP application core, and other portions of the official GIMP distribution not explicitly licensed otherwise, are licensed under the GNU GENERAL PUBLIC LICENSE -- see the 'COPYING' file in this directory for details. ... 'libgimp' and the other GIMP libraries are licensed under the GNU LESSER GENERAL PUBLIC LICENSE -- see the 'COPYING' file in the libgimp directory for details. Отказ от отвественности Данный ответ написан не юристом и служит лишь для ознакомительных целей. Для более развёрнутой консультации предпочтительнее обратиться к специалисту. P.S. В качестве бесплатной альтернативы можно изучить исходники других известных проектов под GNU GPL v2+, в которых используются библиотеки под MIT лицензий и посмотреть каким образом они подошли к данному вопросу.

перетаскивание текста в редакторе Brackets

#редактор #adobe_brackets


В таких текстовых редакторах, как Sublime Text и 
Notepad++ есть возможность перетаскивать текст. Например, Вы выделяете участок текста,
нажимаете на клавишу Ctrl и мышкой перетаскиваете его в нужное место, при этом текст
копируется. Если не нажимать клавишу Ctrl, то текст не копируется, а перемещается.
В редакторе Brackets это не происходит.

Возможно ли в настройках редактора Brackets сделать какие либо изменения, что бы
происходило перетаскивание? Если да, то напишите эту настройку.
    


Ответы

Ответ 1



Отладка / Открыть файл настроек "dragDropText": true

Python. Asyncio. Асинхронные чтение и запись файла

#python #python_3x #асинхронность #asyncio


Как с помощью asyncio реализовать чтение и запись файла ? 
    


Ответы

Ответ 1



Асинхронно никак, но можно в executor'е. import asyncio def read_file(file_name): return open(file_name).read() async def main(): loop = asyncio.get_event_loop() data = await loop.run_in_executor(None, read_file, 'data.txt') print(data) loop = asyncio.get_event_loop() loop.run_until_complete(main())

Progressbar в endlessList

#android #progress_bar


Есть бесконечный список, в котором подгружаю n-oe количество элементов после того
как пролистал до самого низа. Необходимо во время этой подгрузки отображать progressBar
в самом низу. Раньше использовал footerView, состоящего из progressBar, просто скрывал
и отображал его когда было необходимо. Но теперь я использую не listView, а recyclerView,
в который, увы, нельзя стандартными способами вставить header или footer.. Погуглив,
нашел пару библиотек, которые используют свой кастомный адаптер, вместо  RecyclerView.Adapter.
Так не хочется перелопачивать всё в проекте и прикручивать эту "эболу". Может кто сталкивался
с такой проблемой?
    


Ответы

Ответ 1



RecyclerView стал очень удобным в кастомизации, это как Lada, большое поле для фантазий, после выхода с конвейера =) Я недавно также у себя задавался вопросом, как сделать бесконечный список, в итоге сделал так С начала переопределил метод @Override public int getItemViewType(int position) { return isFooter(position) ? TYPE_FOOTER : TYPE_ITEM; } где константы: public static final int TYPE_ITEM = 0; public static final int TYPE_FOOTER = 1; public boolean isFooter(int position) { return mIsFooterEnabled && getItemCount() == position + (mIsFooterEnabled ? 1 : 0); } так как футер не входит в общий массив то дополним метод @Override public int getItemCount() { return mCatalogData != null ? mCatalogData.size() + (mIsFooterEnabled ? 1 : 0) : 0; } футер включаем или выключаем в случае если адаптер реюзаем ну или конец списка. private boolean mIsFooterEnabled; public void setFooterEnabled(boolean isFooterEnabled) { mIsFooterEnabled = isFooterEnabled; } Вот так выглядят Холдеры public static class ProductViewHolder extends RecyclerView.ViewHolder { ProductViewHolder(View itemView) { super(itemView); } } public static class FooterViewHolder extends RecyclerView.ViewHolder { FooterViewHolder(View itemView) { super(itemView); } } И соответственно метод onBindViewHolder @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { if (holder instanceof ProductViewHolder) { ProductViewHolder productViewHolder = (ProductViewHolder) holder; } else { } } ну а в этом методе ставим нужные вью. @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) { if (type == TYPE_ITEM) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.catalog_list_item, viewGroup, false); return new ProductViewHolder(v); } else { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.catalog_list_footer, viewGroup, false); return new FooterViewHolder(v); } } что написано в catalog_list_item кидать не буду, излишне, а в catalog_list_footer просто прогресс бар. UPD Подгрузку начинаю делать, когда покажется вью на экране с позицией getItemCount()-10. mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int position = ((GridLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition(); int updatePosition = recyclerView.getAdapter().getItemCount() - 10; if (position >= updatePosition) { loadNewItems(); } } }); а данные вставляю вот так (Метод внутри адпатера) public void setData(List data) { if (mCatalogData == null) { mCatalogData = new ArrayList<>(); } mCatalogData.addAll(data); notifyItemInserted(getItemCount() - data.size()); }

Ответ 2



Если кому интересно будет, то я сделал таким образом: 1) В разметку с RecyclerView добавил progressBar 2) Далее во фрагменте, к recyclerView вешаю слушатель onScrollListener в котором смотрю, когда необходимо грузить элементы, то показываю свой progressBar if (loading) { if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) { pageNumber++; progressBar.setVisibility(View.VISIBLE); loadList(); loading = false; } } 3) В своём методе loadList() , после загрузки элементов и обновлении адаптера, присваиваю значение loading = true и progressBar.setVisibility(View.GONE). Единственное что остается сделать, это плавное появление progressBara снизу.

Что означает “?” в дженериках?

#java #классы #рефлексия


Изучаю сейчас Reflection. В примере есть строка

Class cls1 = Integer.class;


Что означает знак вопроса?
И почему нельзя просто написать 

Class cls1 = Integer.class;

    


Ответы

Ответ 1



Grundy прав. По идее он может быть полезен в трех случаях. Когда классов обобщения несколько и лишь один нужно оставить неизвестным. Когда вам необходимо одну и ту же переменную инициализировать объектами с разными видами обобщения. Если использовать Object то при инициализации new List будет ошибка, а при вы сможете инициализировать эту переменную и как new List и как new List. Исходя из предыдущего, вы можете определять ее каким-либо интерфейсом или суперклассом , и инициализировать любым классом, который подходит этим критериям, а не только конкретно этим интерфейсом или классом (Этакая двойная фильтрация).

Зависает “Подготовка к установке Ubuntu”

#ubuntu


На компьютере уже стоит винда 8 и убунту, но последняя в не рабочем состоянии (подробности
о неработоспособности можно посмотреть в моем прошлом вопросе), загрузился с флешки,
копировал /home директорию на раздел с данными, пробую переустановить убунту, но она
зависает на моменте "Подготовка к установке Ubuntu", так же всплывает непонятный алерт.



Что не так? Как это пофиксить?

Так же интересует не убьется ли уже существующий grub, в котором есть пункт загрузки
винды при переустановке убунты?

P.S. С ubuntu ковыряюсь 4 день, ответ хотелось бы получить максимально развернутый.
Если надо куда-то залезть и посмотреть какие-то логи, пожалуйста, напишите как залезть
и т.п. Заранее спасибо!
    


Ответы

Ответ 1



Попробуй перезаписать установочную флешку. UNetbootin в помощь!

Зачем в JavaScript использовать паттерн singleton?

#javascript #ооп #шаблоны_проектирования


Разбираюсь с паттернами. Нашёл в интернете, как сделать на JavaScript конструктор,
который бы реализовывал паттерн singleton. Но ведь, как я понимаю, в отличие от многих
ООП языков, в JavaScript можно создавать объекты, не описывая классы (конструкторы),
а просто создать через фигурные скобочки. Получается, можно всегда, когда в JavaScript
нужен singleton, писать не конструктор его реализующий, а просто создавать глобальный
объект, и пользоваться им, присваивая его другим переменным. Подскажите, пожалуйста,
есть ли в этом недостатки в сравнении с созданием конструктора, реализующего singleton?
    


Ответы

Ответ 1



Формально, эти самые 'фигурные скобочки' тоже создаются через конструктор new Object, как и примитивы через обёртки. В пространстве JS, где всё непостоянно и специфично (во всяком случае было когда-то), этот паттерн не очень-то нужен. Сейчас, когда JS вырос из песочницы браузеров и занимает внушительную нишу, он может использовать Singleton для взрослых целей, где после инициализации менять ничего не нужно: одно подключение к БД, один объект пользователя/сессии и пр. Впрочем, с новыми возможностями (Object.seal, Object.preventExtensions, Object.freeze), этот паттерн опять же не нужен - всё решено изящнее и в духе языка (ИМХО).

C++ при записи структуры в файл с помощью fwrite в файле отображаются крякозябры

#cpp


Делаю лабу в универе. Есть структуры, данные которых вводятся с клавиатуры, потом
записываются в файл с помощью функции fwrite(). До сих пор работал только с fstream,
и проблем не возникало. Тут тоже вроде как всё сделал правильно, но на выхлопе получаю
файл device.txt, а в нём сплошные крякозябры. Собираю с под линукса g++. 
Вся программа на гите https://github.com/rotenbergwitalik/laba6.git

код с main:

#include 
#include 

#define DEVICE_NAME_LEN     30
#define MEASUREVALUE_NAME_LEN     30

using namespace std;

struct powerSource {
    float voltage;
    float amperage;
    float periodicity;
};

struct measuredValue {
    char measuredValueName[MEASUREVALUE_NAME_LEN];
    float lowBorder;
    float highBorder;
    float inaccuracy;
};

struct device {
    char deviceName[DEVICE_NAME_LEN];//
    float devicePrice;
    int guarantee; //in month
    struct powerSource devicePowerSource;
    struct measuredValue deviceMeasureValue;
};
int main() {
    struct device labaDevice;

    cout<<"Write name of device: ";
    cin>>labaDevice.deviceName;
    cout<<"Write price of device in $: ";
    cin>>labaDevice.devicePrice;
    cout<<"Write guarantee in month: ";
    cin>>labaDevice.guarantee;

    cout<<"Write power source for device: "<>labaDevice.devicePowerSource.voltage;
    cout<<"\tAmperage: ";
    cin>>labaDevice.devicePowerSource.amperage;
    cout<<"\tPeriodicity: ";
    cin>>labaDevice.devicePowerSource.periodicity;

    cout<<"Write measure value for device: "<>labaDevice.deviceMeasureValue.measuredValueName;
    cout<<"\tLow border: ";
    cin>>labaDevice.deviceMeasureValue.lowBorder;
    cout<<"\tHigh border: ";
    cin>>labaDevice.deviceMeasureValue.highBorder;
    cout<<"\tInaccuracy: ";
    cin>>labaDevice.deviceMeasureValue.inaccuracy;

    FILE* outFile;
    if ((outFile = fopen("device.txt", "wb")) == NULL) {
        cout<<"Con not open the file"<


Ответы

Ответ 1



Думаю, что вы просто раньше выводили поля с помощью оператора вывода в поток <<, т.е. в текстовом виде. fwrite пишет данные в бинарном виде, как есть. Режим wt меняет одно - обработку \n. Если вы хотите получать все данные в текстовом виде, используйте fprintf - типа, вместо outStream << "guarantee = " << labaDevice.guarantee << endl; используйте fprintf(outFile,"guarantee = %d\n",labaDevice.guarantee); Но учтите, что если потом надо будет считывать - то считывать тоже надо будет текстово. А если используете fwrite в бинарном режиме - то потом всю структуру сразу втянете одним fread в том же бинарном режиме...

Ответ 2



"Кракозябры" зависят от того просмотрщика, которым ты этот файл смотришь. Большинство из них пытаются определить кодировку автоматом. Но т. к. файл записывается не текстовый а бинарный, то вполне возможны ошибки. Если под linux, то из консоли можно посмотреть тем же mc F3. После открытия Alt+E и выбираешь ту, которая у тебя стоит - utf-8, например. Да, и лучше переключится в HEX - режим, чтобы просмотрщик не пытался интерпретировать значения из float или int как текст. :) Кстати, имей в виду, что если кодировка у тебя utf-8 и ты используешь не ascii символы, например русские, то длинна строки в байтах может увеличится раза в 3. Так что при вводе имени из 10-15 символов можешь затереть остальные поля структуры мусором или схватить переполнение стека. :)

Ответ 3



Следует исправить строчку (открытие файла в бинарном режиме) if ((outFile = fopen("device.txt", "wb")) == NULL) { на строчку: if ((outFile = fopen("device.txt", "wt")) == NULL) { После этого надо вручную выводить все поля структуры примерно вот так: fwrite("labaDevice.deviceName = ", sizeof("labaDevice.deviceName = "), 1, outFile); fwrite(labaDevice.deviceName, sizeof(labaDevice.deviceName), 1, outFile);

SimpleCursorAdapter + ListView: Чекбоксы теряются при скроллинге

#android #listview #checkbox


Чекбоксы при уходе за экран, теряют свои положения при возвращении. Вот тут - SimpleCursorAdapter
- фильтр для курсора
есть весь код (мой вопрос). Как реализовать метод для сохранения булевых значений?
Неужели вместо курсора в адаптер мне нужно отправлять массив булевых значений? А как
взятие данных через курсор в методе bindView()? Ведь курсор я уберу, а он нужен.

Mетод для получения данных с БД

private void getProductList()
{
    String filter = "list=" + intValue;
    final Cursor cursor = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,
        DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT,
DatabaseProductHelper.PRODUCT_LIST, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, 
        null, null,  null, null, null) ;  
    final Cursor cursorc = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,
                                                    DatabaseProductHelper.PRODUCT_NAME,
DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_LIST, DatabaseProductHelper.PRODUCT_TYPE,
DatabaseProductHelper.PRODUCT_COMPLETE}, 
                                                filter, null,  null, null, null) ;
    final ArrayList arrTblNames = new ArrayList();

    if (cursor.moveToFirst()) {
        while ( !cursor.isAfterLast() ) {
            if(cursor.getInt(cursor.getColumnIndex("list"))==intValue)
            {
            arrTblNames.add(cursor.getString(cursor.getColumnIndex("name")));
            }
            cursor.moveToNext();
            }

        String[] from = {DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT,
DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE};
        int[] to = {R.id.ColMemberID, R.id.ColName, R.id.count_tv, R.id.chb_products};
        adapter = new InteractiveArrayAdapter(ListBuilder.this,
        R.layout.row,
        cursorc,
        from,
        to
        );
        //lv_products.setAdapter(adapter);

    }



    if(!arrTblNames.isEmpty()){
        empty_bd_layout.setAlpha(0);
        lv_products.setAdapter(adapter);
    }
    else{
empty_bd_layout.setAlpha(255);
}
}


И сам адаптер

public class InteractiveArrayAdapter extends SimpleCursorAdapter
{
    private int layout;
    private boolean checked[];
    public InteractiveArrayAdapter(Context _context, int _layout, Cursor _cursor,
String[] _from, int[] _to) {
        super(_context, _layout, _cursor, _from, _to);
        layout = _layout;
        int counts = _cursor.getCount();
        checked = new boolean[counts];

                for (int i = 0; i < counts; i++){

                    int checkMarker = _cursor.getInt(_cursor.getColumnIndex("complete"));
                    checked[i] = checkMarker == 1;
            }


    }

    @Override
    public void bindView(View view, Context _context, Cursor _cursor) {




        String prod_name = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_NAME));
        String prod_count = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COUNT));
        String prod_type = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_TYPE));
    //  int prod_complete = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE));
        TextView name_prod_tv = (TextView)view.findViewById(R.id.ColMemberID);
        TextView count_prod_tv = (TextView)view.findViewById(R.id.ColName);
        TextView type_prod_tv = (TextView)view.findViewById(R.id.count_tv);
        CheckBox chb = (CheckBox)view.findViewById(R.id.chb_products);

        chb.setFocusable(false);

        chb.setClickable(false);

        name_prod_tv.setText(prod_name);

        count_prod_tv.setText(prod_count);

        type_prod_tv.setText(prod_type);

        chb.setChecked(checked[_cursor.getPosition()]);

        }
    @Override
    public View newView(Context _context, Cursor _cursor, ViewGroup _parent)
    {
        LayoutInflater inflater = (LayoutInflater)_context.getSystemService(_context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(layout, _parent, false);
        return view;
    }
    public void setChecked(int position){
        // инвертируем значение при обработке клика этим методом
        checked[position]=!checked[position];
    }
}


LogCat
FATAL EXCEPTION: main
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               Process:
ru.diskrim.listbuy, PID: 1468
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               java.lang.RuntimeException:
Unable to start activity ComponentInfo{ru.diskrim.listbuy/ru.diskrim.listbuy.ListBuilder}:
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 4
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.access$800(ActivityThread.java:151)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.os.Handler.dispatchMessage(Handler.java:102)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.os.Looper.loop(Looper.java:135)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.main(ActivityThread.java:5254)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
java.lang.reflect.Method.invoke(Native Method)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
java.lang.reflect.Method.invoke(Method.java:372)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
de.robv.android.xposed.XposedBridge.main(XposedBridge.java:117)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               Caused
by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 4
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:68)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
ru.diskrim.listbuy.ListBuilder$InteractiveArrayAdapter.(ListBuilder.java:245)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
ru.diskrim.listbuy.ListBuilder.getProductList(ListBuilder.java:209)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
ru.diskrim.listbuy.ListBuilder.onCreate(ListBuilder.java:184)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.Activity.performCreate(Activity.java:6033)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               ...
11 more
    


Ответы

Ответ 1



Решение мало чем отличается от этого ответа, с той разницей, что вам нужно обрабатывать клики из активити, а не слушателем в адаптере. Поскольку мы не можем изменять значения в курсоре, а только читать их оттуда, для запоминания текущего состояния чекбоксов требуется создать локальное хранилище. В адаптер вам нужно передавать данные, которые должны быть отображены в виджете, в вашем случае это курсор с выборкой из БД. Вспомогательный массив булевых значений никуда передавать не нужно, он создается внутри адаптера. Примерная реализация может выглядеть так: private void getProductList() { // Если требуется только имя, следует и запрашивать из БД только //колонку с именем, а не все в кучу // Если требуется только записи с каким то условием, то их и надо запрашивать, // а не все в подряд, а потом выбирать нужные каким то циклом // так же эти данные включены и в курсор для адаптера и нет нужды // получать то же самое дважды // final Cursor cursor = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID, DatabaseProductHelper.PRODUCT_NAME,"list = ?", new String[] {""+ intValue}, null, null, null) ; //то же самое, только нужные в адаптере колонки final Cursor cursorc = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, "list = ?", new String[] {""+ intValue}, null, null, null); final ArrayList arrTblNames = new ArrayList(); // копирование данных из курсора в массив сильно упрощается, // так как у нас только нужные данные while ( cursorc.moveToNext() ) { arrTblNames.add(cursorc.getString(cursorc.getColumnIndex("name"))); } String[] from = {DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}; int[] to = {R.id.ColMemberID, R.id.ColName, R.id.count_tv, R.id.chb_products}; adapter = new InteractiveArrayAdapter(ListBuilder.this, R.layout.row, cursorc, from, to ); //lv_products.setAdapter(adapter); } // у виджетов есть свойство Visiblity, которое управляет видимостью на // экране, зачем тут использовать прозрачность ? // я бы поменял всю логику вообще, исходя из условия ниже, // зачем получаnь и формировать данные, если они могут не понадобится if(!arrTblNames.isEmpty()){ empty_bd_layout.setAlpha(0); lv_products.setAdapter(adapter); } else{ empty_bd_layout.setAlpha(255); } } адаптер: public class InteractiveArrayAdapter extends SimpleCursorAdapter { private int layout; private boolean checked[]; public InteractiveArrayAdapter(Context _context, int _layout, Cursor _cursor, String[] _from, int[] _to) { super(_context, _layout, _cursor, _from, _to); layout = _layout; // инициализируем вспомогательный массив начальными отметками чекбоксов из курсора checked = new boolean[_cursor.getCount()]; int i = 0; while ( _cursor.moveToNext() ) { int checkMarker = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); checked[i] = (checkMarker == 1) ? true: false; i = i + 1; } // нужно вернуть указатель курсора в первоначальное положение // перед первой записью, для корректной работы адаптера _cursor.moveToPosition(-1); } @Override public void bindView(View view, Context _context, Cursor _cursor) { String prod_name = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_NAME)); String prod_count = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COUNT)); String prod_type = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_TYPE)); // эта строка здесь теперь по видимому не нужна, поскольку значения отметок // из курсора мы уже извлекли //int prod_complete = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); TextView name_prod_tv = (TextView)view.findViewById(R.id.ColMemberID); TextView count_prod_tv = (TextView)view.findViewById(R.id.ColName); TextView type_prod_tv = (TextView)view.findViewById(R.id.count_tv); CheckBox chb = (CheckBox)view.findViewById(R.id.chb_products); chb.setFocusable(false); chb.setClickable(false); name_prod_tv.setText(prod_name); count_prod_tv.setText(prod_count); type_prod_tv.setText(prod_type); // устанавливаем чекбоксы по вспомогательному массиву, а не по курсору // получаем текущую позицию курсора (и соответственно адаптера) через его метод chb.setChecked(checked[_cursor.getPosition()]); } @Override public View newView(Context _context, Cursor _cursor, ViewGroup _parent) { LayoutInflater inflater = (LayoutInflater)_context.getSystemService(_context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(layout, _parent, false); return view; } // метод для фиксации изменений отметок чекбоксов из активити public void setChecked(int position){ // инвертируем значение при обработке клика этим методом checked[position] = !checked[position]; } } запись изменений в БД по отметкам чекбоксов у вас, насколько я помню, осуществляется при обработке клика в слушателе списка, поэтому в адаптер это действие не включено, но оно должно обязательно присутствовать, иначе при выходе из списка отметки будут утеряны.

Yii2 и Яндекс Касса

#php #yii2 #яндекс


Три часа борюсь с яндекс кассой. Саппорт говорит  что у меня сайт не принимает POST
запросы и возвращает bad request #400. Сайт на Yii2. Есть предположение что это из
за ckrf токена. Может быть кто то сталкивался и сможет мне помочь?
    


Ответы

Ответ 1



В контроллере реализуйте метод beforeAction таким образом. public function beforeAction($action) { $this->enableCsrfValidation = false; return parent::beforeAction($action); } Если не хотите отключать CSRF для всех действий, то можете отключить для определенных действий: public function beforeAction($action) { if ($action->id === 'test') $this->enableCsrfValidation = false; return parent::beforeAction($action); } В данном случае мы отключили CSRF для действия test

Ответ 2



Для нескольких экшенов: public function beforeAction($action) { $this->enableCsrfValidation = !in_array($action->id, ['check', 'aviso']); return parent::beforeAction($action); }

JavaFX 8 3D : провести Cylinder от точки А до точки B, заданных Point3D объектами

#java #javafx #3d


Возникла необходимость соединить две точки цилиндром.
Есть координаты двух точек, заданных, как экземпляры Point3D:

Point3D pointA = new Point3D(100,200,150);
Point3D pointB = new Point3D(200,150,-100);


Есть группа (javafx.scene.Group), в которой производятся построения:

Group space3D = new Group();


Задача: соединить эти две виртуальные точки (можно разместить в этих координатах
по экземпляру Sphere радиусом 10, для наглядности) экземпляром javafx.scene.shape.Cylinder
радиусом 2, высотой равной расстоянию от точки А до точки B с минимальным количеством
действий.

П.С.: Какие альтернативы были бы более эффективными для визуального соединения двух
точек в 3D пространстве?
    


Ответы

Ответ 1



Начну от обратного.Пример решения: public Cylinder paintCylinder(Point3D A, Point3D B) { Point3D temp = A.subtract(B); double Y = temp.getX() != 0 || temp.getZ() != 0 ? B.getY() : B.getY() > A.getY() ? B.getY() : A.getY(); Point3D dir = A.subtract(B).crossProduct(new Point3D(0, -1, 0)); double angle = Math.acos(A.subtract(B).normalize().dotProduct(new Point3D(0, -1, 0))); double h1 = A.distance(B); Cylinder c = new Cylinder(2d, h1); c.getTransforms().addAll(new Translate(B.getX(), Y - h1 / 2d, B.getZ()), new Rotate(-Math.toDegrees(angle), 0d, h1 / 2d, 0d, new Point3D(dir.getX(), -dir.getY(), dir.getZ()))); return c; } Как результат: : теперь ближе к конкретным вопросам: Так сложилось что легче для понимания процедуры вращения объекта это последовательное вращение по 3 координатам (и применяется такой подход часто) Но если разобраться то вполне естественный ход поворачивать объект всего один раз на один конкретный угол.И если быть совсем точным поворачивают систему координат дабы на одной плоскости оказались точки начала и конца дуги поворота. Возможна также работа с матрицей поворота и как пример работы с ней данный ответ.Да конечно такой подход быстрее чем работа с последовательным поворотом по трем осям но хочу заметить что сам автор ответа(он же к слову и разработчик библиотеки - FXyz) по моим наблюдениям конкретно матричной реализацией не пользуется (наблюдение рамках открытого кода на GitHub).